Wednesday, February 3, 2010

Autodesk Map3d 2010 with WCF (III)

Author: Jonio, Dennis

The snippets below are an example for a client. It did take some time to research the parameters required for a long lived(8 hour) service. It turned out to be that two(2) parameters have to be set, InactivityTimeout and ReceiveTimeout. Needless to say these should match the service’s ServiceEndpoint configuration.

In general the way the service works is that you can send it data with any one(1) of three(3) different methods. I only employ one(1) of those methods in this case. If your application has “Subscribed” you will be sent via the callback method any and all output from the service. I really do not attempt to track the “state” of anything. As the book explains, and to say the least, state tracking is probably not the best way to expend your time and energy.

From Map3d's perspective the new, improved DataBridge is really a non issue. For all intent and purpose Map3d will see things the same way. I am sure that as time moves on the complexity of "if" and "case" statements will grow.
I plan on following this article with the complete DataBridge Version II.
Source code snippets for a client(C#):


public static IByteSrvcWCallback SrvcHost;
public static ByteSrvcCallbackImpl callbackImpl;
public static DuplexChannelFactory dcf;
public static Guid MyServicedName;
public static string MyPrefixForMap3dDQ = "MDADCLSSFYIO";
public static string AddressOfReliableSessionService = "net.tcp://localhost:9080/DataService";


public MainForm()
{
InitializeComponent();
NetTcpBinding ntb = new NetTcpBinding(SecurityMode.None, true);
ntb.ReliableSession.Enabled = true;
ntb.ReliableSession.Ordered = true;
ntb.ReliableSession.InactivityTimeout = new TimeSpan(0, 8, 0, 0);
ntb.ReceiveTimeout = new TimeSpan(0, 8, 0, 0);
callbackImpl = new ByteSrvcCallbackImpl();
InstanceContext ic = new InstanceContext(callbackImpl);
dcf = new DuplexChannelFactory(
ic,
ntb,
new EndpointAddress(AddressOfReliableSessionService));
SrvcHost = dcf.CreateChannel();
callbackImpl.OnGotControlPacket +=
new ByteSrvcCallbackImpl.GotControlPacket(WCF_RcvdSrvcControlPacket);
MyServicedName = Guid.Empty;
}

void WCF_RcvdSrvcControlPacket(byte[] ba)
{
byte[] x = callbackImpl.ControlPacket;
//
//Here is the callback
//Do something useful with the data that the Service has sent to you
//
}

public int WCF_SendToMap3dDataBridge(byte[] ba)
{
return SrvcHost.DQPipedIn(MyPrefixForMap3dDQ, ba);
}

private void btnSUBSCRIBE_Click(object sender, EventArgs e)
{
try
{
if (MyServicedName == Guid.Empty)
MyServicedName = SrvcHost.Subscribe();
}
catch (EndpointNotFoundException _epnfX)
{
AppendMessage("EndPoint ERROR: " + _epnfX.Message);
}
catch (System.Exception _eX)
{
AppendMessage("ERROR: " + _eX.Message);
}
}

private void btnUNSUBSCRIBE_Click(object sender, EventArgs e)
{
try
{
if (MyServicedName != Guid.Empty)
SrvcHost.UnSubscribe(MyServicedName);
MyServicedName = Guid.Empty;
}
catch (EndpointNotFoundException _epnfX)
{
AppendMessage("EndPoint ERROR: " + _epnfX.Message);
}
catch (System.Exception _eX)
{
AppendMessage("ERROR: " + _eX.Message);
}
}

Monday, February 1, 2010

Autodesk Map3d 2010 with WCF (II)

Author: Jonio, Dennis

I make absolutely no attempt here to explain why I have done the things the way I have done them in relationship to the grand scheme of WCF. There is just too much to explain and you really should get the book and improve on what I have done. I stopped a long time ago in trying to force Map3d to do multi-threading. As it turns out this is not debilitating at all, just use a Form.
The following are my concrete classes for the WCF interfaces found in the previous article. Making no value judgments, you do have to be impressed with how much Microsoft has done in producing the “behind the scenes” transport functionality. Since I wanted “required, reliable sessions with binary transport” I have coded towards the NetTcpBinding and the NetNamedPipeBinding.
As you can see there are two(2) methods for getting data to the service and the service has one(1) method to send data back to the client. During research I happened upon this multiple client subscription concept with a simple Guid identifier. I desperately wanted some kind of "session identifier" that was all ready in place, generic and robust. If you do the reading you will discover WCF has the concept of SessionId but in my mind's eye it is too crippled to be of any use for my purpose. This subscription paradigm struck me as a good, simple and straightforward idea.
The service itself.
Source code (C#):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace DplXByteSrvcs
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class ByteSrvcWCallbackImpl : IByteSrvcWCallback
{
public delegate void DataIsReady(byte[] hotData);
public DataIsReady DataReady = null;

public delegate void DQDataIsReady(string destinationQ, byte[] hotData);
public DQDataIsReady DQDataReady = null;

public delegate void GotControlPacket(byte[] hotPacket);
public GotControlPacket OnGotControlPacket = null;

public readonly Dictionary SrvcClients =
new Dictionary();

public void ControlPacket(byte[] ba)
{
int rtnval = 0;
if (ba != null)
rtnval = ba.Length;
if (OnGotControlPacket != null)
OnGotControlPacket(ba);

IByteSrvcCallback callback = OperationContext.Current.GetCallbackChannel();
if (!SrvcClients.ContainsValue(callback))
{
Guid clientId = Guid.NewGuid();
if (callback != null)
{
lock (SrvcClients)
{
SrvcClients.Add(clientId, callback);
}
}
}
}
public int PipedIn(byte[] data)
{
int rtnval = 0;
if (data != null)
rtnval = data.Length;

if (DataReady != null)
DataReady(data);

return rtnval;
}
public int DQPipedIn(string destinationQ, byte[] data)
{
int rtnval = 0;
if (data != null)
rtnval = data.Length;

if (DQDataReady != null)
DQDataReady(destinationQ, data);

return rtnval;
}
Guid IByteSrvcWCallback.Subscribe()
{
IByteSrvcCallback callback =
OperationContext.Current.GetCallbackChannel();
Guid clientId = Guid.NewGuid();
if (callback != null)
{
lock (SrvcClients)
{
SrvcClients.Add(clientId, callback);
}
}
return clientId;
}
void IByteSrvcWCallback.UnSubscribe(Guid clientGID)
{
lock (SrvcClients)
{
if (SrvcClients.ContainsKey(clientGID))
{
SrvcClients.Remove(clientGID);
}
}
}
void IByteSrvcWCallback.NoOpButKeepAlive() { }

}//EOC
}//EONS


You will discover as I did that the communications piece is really all about the client. Nothing much happens without them.
Now for the Client the callback class.
Source code (C#):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DplXByteSrvcs
{
public class ByteSrvcCallbackImpl : IByteSrvcCallback
{
public delegate void GotControlPacket(byte[] hotPacket);
public GotControlPacket OnGotControlPacket = null;

private byte[] m_ba;
public byte[] ControlPacket
{
get { return m_ba; }
}
public void SentControlPacket(byte[] ba)
{
m_ba = ba;
if (OnGotControlPacket != null)
OnGotControlPacket(ba);
}
}
}

Autodesk Map3d 2010 and WCF (I)

Author: Jonio, Dennis

Well, I finally finished my first Windows Communication Foundation(WCF) project. Ever since .NET Framework 3.0 came out I had been curious but until now the chance to delve into it just never appeared. The prompt was to get some flexibility into the IPC chores between my custom Autodesk application modules(netloads) and my .NET applications.
First off, I certainly join the chorus that promotes getting Juval Lowy’s work Programming WCF Services (in my case 2nd Edition). There is a multitude of nuance and subtlety that would be left to chance without reading this work. In addition I do not have a clue where else a person would go to get his kind of depth of understanding. A real "must have" if you are serious about WCF.
As I spent more time with WCF I certainly learned of some of its strengths and weakness’. I really did waiver a lot concerning implementing the callback interface versus just using the simplest of operation contracts with each executable acting as a hosting service and likewise a client. This would have made this new interface very similar to my previous NamedPipe interface in that both sides act as host and client. In the end I choose the WCF DuplexChannel/callback paradigm because I figured out the rather straightforward way to keep the session(s) alive over an extended period of time.
If you are at all familiar with my previous work with IPC you know that I pass serialized datasets around as opposed to passing more granular objects. I do not stray from this paradigm. It has served me well and I cannot think of any reason to change.

The following are my interface definitions for the service and callback. I will leave the class implementation for a follow up.
Source code (C#):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace DplXByteSrvcs
{
[ServiceContract(Namespace = "WCF.MDAD.SERVICES",
CallbackContract = typeof(IByteSrvcCallback),
SessionMode = SessionMode.Required)]
public interface IByteSrvcWCallback
{
[OperationContract(IsOneWay = true)]
void ControlPacket(byte[] baIn);

[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
int PipedIn(byte[] data);

[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
int DQPipedIn(string destinationQ, byte[] data);

[OperationContract]
Guid Subscribe();
[OperationContract(IsOneWay = true)]
void UnSubscribe(Guid clientId);
[OperationContract(IsOneWay = true)]
void NoOpButKeepAlive();

}
public interface IByteSrvcCallback
{
[OperationContract(IsOneWay = true)]
void SentControlPacket(byte[] baOut);
}
}

Thursday, November 19, 2009

(VII) New SDO_GEOMETRY <-> Autodesk Map3d 2010

Author: Jonio, Dennis

The next and last items on the list ...
  • Given one or more Autodesk/Map3d objects decompose it(them) into “Drawable(s)”.
  • Given a “DrawAble” compose a Autodesk/Map3d object.

    This is the class that interacts with Autodesk Map3d. (I have removed a few things that are not importtant to the discussion here.)
    First, as time has gone on I have grown weary of parseing out Autodesk/Map3d objects and manipulating them. I gravitated toward AppendLoopFromBoundary() and BalanceTree() for MPolygon construction. Just a lot less code on my part. If it isn't a Point type I force just about everything to a Polyline at one time or the other. If you really need true 3D objects you shouldn't be reading this anyway.
    Just some things of note:
  • I never output an Oracle Circle
  • I never output an Oracle Rectangle
  • I never output an Oracle SDO_POINT
    I will read them and write them as Autdesk objects but after this they loose their identity as such.

    This is the last post on this topic. I have decided NOT to post the working source and project. If you are interested in the final work leave a comment with your email address.

    Since I produce only VALIDATED geometry I will be working on the post of my latest iteration of my IO class for doing validation against the database.
    Source code (C#):

    using MDADDrawAbles;
    using SDO = MDADDrawAbles.DrawAbleSdoGeometryUtil;

    using NetSdoGeometry;

    namespace MDADDrawAbleDwg
    {
    public class DrawAbleDwg
    {
    //
    // POINT
    //
    public static DrawAble PointDrawAbleFromPoint(Point3d p3d, int _dimensionality)
    {
    DrawAble dp = new DrawAble(DrawAbleType.Point, _dimensionality);
    DrawAbleSubComponent dpc = new DrawAbleSubComponent();
    dpc.Etype = DrawAbleSubComponentEType.Point;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dpc.Ords = new decimal[len];
    dpc.Ords[0] = System.Convert.ToDecimal(p3d.X);
    dpc.Ords[1] = System.Convert.ToDecimal(p3d.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dpc.Ords[2] = System.Convert.ToDecimal(p3d.Z);
    dp.SubComponents.Add(dpc);
    return dp;
    }
    public static DrawAble PointDrawAbleFromPoint(DBPoint dbp, int _dimensionality)
    {
    DrawAble dp = new DrawAble(DrawAbleType.Point, _dimensionality);
    DrawAbleSubComponent dpc = new DrawAbleSubComponent();
    dpc.Etype = DrawAbleSubComponentEType.Point;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dpc.Ords = new decimal[len];
    dpc.Ords[0] = System.Convert.ToDecimal(dbp.Position.X);
    dpc.Ords[1] = System.Convert.ToDecimal(dbp.Position.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dpc.Ords[2] = System.Convert.ToDecimal(dbp.Position.Z);
    dp.SubComponents.Add(dpc);
    return dp;
    }
    //
    // POINT CLUSTER
    //
    public static DrawAble PointClusterDrawAbleFromPointList(List p3dList, int _dimensionality)
    {
    DrawAble dp = new DrawAble(DrawAbleType.Point, _dimensionality);
    DrawAbleSubComponent dpc = new DrawAbleSubComponent();
    dpc.Etype = DrawAbleSubComponentEType.PointCluster;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dpc.Ords = new decimal[len * p3dList.Count];
    int p3d_counter = 0;
    for (int _k = 0; _k < dpc.Ords.Length; )
    {
    dpc.Ords[_k] = System.Convert.ToDecimal(p3dList[p3d_counter].X);
    dpc.Ords[_k + 1] = System.Convert.ToDecimal(p3dList[p3d_counter].Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dpc.Ords[_k + 2] = System.Convert.ToDecimal(p3dList[p3d_counter].Z);
    _k = _k + len;
    p3d_counter = p3d_counter + 1;
    }
    dpc.Elem = new int[] { 0, 1, p3dList.Count };
    dp.SubComponents.Add(dpc);
    return dp;
    }
    //
    // LINES
    //
    public static DrawAble LineCurveDrawAbleFromPolyline(Polyline pl, Polyline2d pl2d, Polyline3d pl3d, int _dimensionality)
    {
    DrawAble dl = new DrawAble(DrawAbleType.Line, _dimensionality);
    int hasBulgesCount = 0;
    Point3dCollection tmppts = null;
    DoubleCollection tmpblgs = null;
    Point3d[] pts = null;
    double[] blgs = null;
    if (pl != null)
    {
    tmppts = new Point3dCollection();
    tmpblgs = new DoubleCollection();
    int i = 0;
    for (; i < pl.NumberOfVertices; i++)
    {
    switch (pl.GetSegmentType(i))
    {
    case SegmentType.Arc:
    CircularArc2d ca2d = pl.GetArcSegment2dAt(i);
    double bulge = GetBulge2d(ca2d);
    tmpblgs.Add(bulge);
    tmppts.Add(new Point3d(ca2d.StartPoint.X, ca2d.StartPoint.Y, pl.GetPoint3dAt(i).Z));
    hasBulgesCount++;
    ca2d.Dispose();
    break;
    default:
    tmpblgs.Add(0.0);
    tmppts.Add(new Point3d(pl.GetPoint3dAt(i).X, pl.GetPoint3dAt(i).Y, pl.GetPoint3dAt(i).Z));
    break;
    }
    }
    // Do NOT duplicate any point ... this appears to have different behavior for
    // the 2D and 3D polylines so we will check them all.
    if (pl.Closed && (tmppts[0].IsEqualTo(tmppts[tmppts.Count - 1]) == false))
    {
    //tmppts.Add(new Point3d(pl.GetPoint2dAt(0).X, pl.GetPoint2dAt(0).Y, 0.0));
    tmppts.Add(new Point3d(pl.GetPoint3dAt(0).X, pl.GetPoint3dAt(0).Y, pl.GetPoint3dAt(0).Z));
    tmpblgs.Add(0.0);
    }
    // Now we can dimensions our array stuctures and fill them up
    pts = new Point3d[tmppts.Count];
    blgs = new double[tmppts.Count];
    for (int z = 0; z < tmppts.Count; z++)
    {
    pts[z] = new Point3d(tmppts[z].X, tmppts[z].Y, tmppts[z].Z);
    blgs[z] = tmpblgs[z];
    }
    tmppts.Clear();
    tmppts.Dispose();
    tmpblgs.Clear();
    }
    //END OF POLYLINE
    //START OF POLYLINE2D
    if (pl2d != null)
    {
    // No way of knowing how many we have so we need this to collect the points
    tmppts = new Point3dCollection();
    tmpblgs = new DoubleCollection();
    if (pl2d.PolyType == Poly2dType.SimplePoly)
    {
    Transaction t = pl2d.Database.TransactionManager.StartTransaction();
    IEnumerator iterate = pl2d.GetEnumerator();
    while (iterate.MoveNext())
    {
    ObjectId id = (ObjectId)iterate.Current;
    Vertex2d vertex = (Vertex2d)t.GetObject(id, OpenMode.ForRead);
    tmppts.Add(vertex.Position);
    tmpblgs.Add(vertex.Bulge);
    if (vertex.Bulge != 0.0)
    hasBulgesCount++;
    }
    t.Abort();
    t.Dispose();
    }
    else
    {
    DBObjectCollection collection = new DBObjectCollection();
    pl2d.Explode(collection);
    foreach (Line line in collection)
    {
    tmppts.Add(line.StartPoint);
    tmpblgs.Add(0.0);
    tmppts.Add(line.EndPoint);
    tmpblgs.Add(0.0);
    }
    collection.Dispose();
    }
    // Do NOT duplicate any point
    if (pl2d.Closed && (tmppts[0].IsEqualTo(tmppts[tmppts.Count - 1]) == false))
    {
    tmppts.Add(tmppts[0]);
    tmpblgs.Add(0.0);
    }
    // Now we can dimensions our array stuctures and fill them up
    pts = new Point3d[tmppts.Count];
    blgs = new double[tmppts.Count];
    for (int z = 0; z < tmppts.Count; z++)
    {
    pts[z] = new Point3d(tmppts[z].X, tmppts[z].Y, tmppts[z].Z);
    blgs[z] = tmpblgs[z];
    }
    tmppts.Clear();
    tmppts.Dispose();
    tmpblgs.Clear();
    }
    //END OF POLYLINE2D
    //START OF POLYLINE3D
    if (pl3d != null)
    {
    tmppts = new Point3dCollection();
    tmpblgs = new DoubleCollection();
    if (pl3d.PolyType == Poly3dType.SimplePoly)
    {
    Transaction t = pl3d.Database.TransactionManager.StartTransaction();
    IEnumerator iterator = pl3d.GetEnumerator();
    while (iterator.MoveNext())
    {
    ObjectId id = (ObjectId)iterator.Current;
    PolylineVertex3d vertex3d = (PolylineVertex3d)t.GetObject(id, OpenMode.ForRead);
    tmppts.Add(vertex3d.Position);
    tmpblgs.Add(0.0);
    }
    t.Abort();
    t.Dispose();
    }
    else
    {
    DBObjectCollection collection = new DBObjectCollection();
    pl3d.Explode(collection);
    foreach (Line line in collection)
    {
    tmppts.Add(line.StartPoint);
    tmpblgs.Add(0.0);
    tmppts.Add(line.EndPoint);
    tmpblgs.Add(0.0);
    }
    collection.Dispose();
    }
    // Do NOT duplicate any point
    if (pl3d.Closed && (tmppts[0].IsEqualTo(tmppts[tmppts.Count - 1]) == false))
    {
    tmppts.Add(tmppts[0]);
    tmpblgs.Add(0.0);
    }
    // Now we can dimensions our array stuctures and fill them up
    pts = new Point3d[tmppts.Count];
    blgs = new double[tmppts.Count];
    for (int z = 0; z < tmppts.Count; z++)
    {
    pts[z] = new Point3d(tmppts[z].X, tmppts[z].Y, tmppts[z].Z);
    blgs[z] = tmpblgs[z];
    }
    tmppts.Clear();
    tmppts.Dispose();
    tmpblgs.Clear();
    }
    //END OF POLYLINE3D
    //
    // Finished getting all the ordinates and bulges for this linecurve
    //
    DrawAbleSubComponent dlc = new DrawAbleSubComponent();
    if (hasBulgesCount == 0)
    {
    dlc.Etype = DrawAbleSubComponentEType.SimpleLine;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dlc.Ords = new decimal[len * pts.Length];
    int pts_counter = 0;
    for (int _k = 0; _k < dlc.Ords.Length; )
    {
    dlc.Ords[_k] = System.Convert.ToDecimal(pts[pts_counter].X);
    dlc.Ords[_k + 1] = System.Convert.ToDecimal(pts[pts_counter].Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[_k + 2] = System.Convert.ToDecimal(pts[pts_counter].Z);
    _k = _k + len;
    pts_counter = pts_counter + 1;
    }
    dl.SubComponents.Add(dlc);
    }
    else if (hasBulgesCount == pts.Length - 1)
    {
    dlc.Etype = DrawAbleSubComponentEType.SimpleLineAllCurves;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dlc.Ords = new decimal[(len * pts.Length) + (hasBulgesCount * len)];
    int ords_counter = 0;
    Point3d arc_endpoint;

    for (int j = 0; j < pts.Length; j++)
    {
    double theBulge = blgs[j];
    arc_endpoint = pts[j + 1];
    CircularArc2d ca2d = new CircularArc2d(
    new Point2d(pts[j].X, pts[j].Y),
    new Point2d(arc_endpoint.X, arc_endpoint.Y), theBulge, false);

    Interval interval_of_arc = ca2d.GetInterval();
    Point2d somePointOnArc = ca2d.EvaluatePoint(interval_of_arc.Element / 2);
    //Start
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);
    //Center point on arc
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(somePointOnArc.X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(somePointOnArc.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);

    //Because of LOOK-AHEAD we now check for the end
    if (j == (pts.Length - 2))
    {
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(arc_endpoint.X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(arc_endpoint.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(arc_endpoint.Z);
    j = pts.Length; //End the loop
    }
    }
    dl.SubComponents.Add(dlc);
    }
    else
    {
    //DIM_ELEMENTS are required
    dlc.Etype = DrawAbleSubComponentEType.CompoundLine;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dlc.Ords = new decimal[(len * pts.Length) + (hasBulgesCount * len)];
    int ords_counter = 0;
    Point3d arc_endpoint;

    TriInts elmHeader = new TriInts(ords_counter, SDO.BasicETYPE(DrawAbleSubComponentEType.CompoundLine), 0);
    List elmList = new List();
    TriInts wrkrElm = null;
    int nxtINTERP = 0;
    int lstINTERP = 0;
    for (int j = 0; j < pts.Length; j++)
    {
    if (j < pts.Length - 1)
    nxtINTERP = (blgs[j] == 0.0) ? (int)SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleLine) : (int)SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleLineAllCurves);

    if (lstINTERP != nxtINTERP)
    {
    if (wrkrElm != null)
    elmList.Add(wrkrElm);
    wrkrElm = new TriInts(ords_counter, SDO.BasicETYPE(DrawAbleSubComponentEType.SimpleLineAllCurves), nxtINTERP);
    lstINTERP = nxtINTERP;
    }

    double theBulge = blgs[j];
    if (theBulge != 0.0)
    {
    arc_endpoint = pts[j + 1];
    CircularArc2d ca2d = new CircularArc2d(
    new Point2d(pts[j].X, pts[j].Y),
    new Point2d(arc_endpoint.X, arc_endpoint.Y), theBulge, false);

    Interval interval_of_arc = ca2d.GetInterval();
    Point2d somePointOnArc = ca2d.EvaluatePoint(interval_of_arc.Element / 2);
    //Start
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);
    //Center point on arc
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(somePointOnArc.X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(somePointOnArc.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);
    }
    else
    {
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);
    }

    }//for loop
    elmList.Add(wrkrElm);
    elmHeader.INTERP = elmList.Count;
    dlc.Elem = new int[(elmList.Count + 1) * 3];
    int cntr = 0;
    dlc.Elem[cntr++] = elmHeader.OFFSET;
    dlc.Elem[cntr++] = elmHeader.ETYPE;
    dlc.Elem[cntr++] = elmHeader.INTERP;
    for (int _i = 0; _i < elmList.Count; _i++)
    {
    dlc.Elem[cntr++] = elmList[_i].OFFSET;
    dlc.Elem[cntr++] = elmList[_i].ETYPE;
    dlc.Elem[cntr++] = elmList[_i].INTERP;
    }
    dl.SubComponents.Add(dlc);
    }
    return dl;
    }
    public static DrawAble LineCurveDrawAbleFromArc(Arc a, int _dimensionality)
    {
    DrawAble d = new DrawAble(DrawAbleType.Line, _dimensionality);
    DrawAbleSubComponent dc = new DrawAbleSubComponent();
    dc.Etype = DrawAbleSubComponentEType.SimpleLineAllCurves;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dc.Ords = new decimal[len * 3];
    double length = a.GetDistAtPoint(a.EndPoint);
    Point3d mid = a.GetPointAtDist(length / 2.0);
    int ords_counter = 0;
    //Start
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(a.StartPoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(a.StartPoint.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(a.StartPoint.Z);
    //Mid
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(mid.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(mid.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(mid.Z);
    //End
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(a.EndPoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(a.EndPoint.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(a.EndPoint.Z);
    d.SubComponents.Add(dc);

    return d;
    }
    public static DrawAble LineCurveDrawAbleFromLine(Line l, int _dimensionality)
    {
    DrawAble d = new DrawAble(DrawAbleType.Line, _dimensionality);
    DrawAbleSubComponent dc = new DrawAbleSubComponent();
    dc.Etype = DrawAbleSubComponentEType.SimpleLine;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dc.Ords = new decimal[len * 2];
    int ords_counter = 0;
    //Start
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(l.StartPoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(l.StartPoint.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(l.StartPoint.Z);
    //End
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(l.EndPoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(l.EndPoint.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(l.EndPoint.Z);
    d.SubComponents.Add(dc);

    return d;
    }
    public static DrawAble LineCurveDrawAbleFromCircle(Circle circ, int _dimensionality)
    {
    DrawAble d = new DrawAble(DrawAbleType.Line, _dimensionality);
    DrawAbleSubComponent dc = new DrawAbleSubComponent();
    dc.Etype = DrawAbleSubComponentEType.SimpleLineAllCurves;
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? 15 : 10;
    dc.Ords = new decimal[len];
    int ords_counter = 0;
    double length = circ.Circumference;
    Point3d firstarc_endpoint = circ.GetPointAtDist(length / 2.0);
    Point3d firstarc_midpoint = circ.GetPointAtDist((length / 2.0) / 2.0);
    Point3d secondarc_midpoint = circ.GetPointAtDist(length * .75);
    //Start
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(circ.StartPoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(circ.StartPoint.Y);
    if (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(circ.StartPoint.Z);
    //mid 1
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(firstarc_midpoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(firstarc_midpoint.Y);
    if (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(firstarc_midpoint.Z);
    //End
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(firstarc_endpoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(firstarc_endpoint.Y);
    if (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(firstarc_endpoint.Z);
    //mid 2
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(secondarc_midpoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(secondarc_midpoint.Y);
    if (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(secondarc_midpoint.Z);
    //End
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(circ.EndPoint.X);
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(circ.EndPoint.Y);
    if (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dc.Ords[ords_counter++] = System.Convert.ToDecimal(circ.EndPoint.Z);

    d.SubComponents.Add(dc);

    return d;
    }
    //
    // SURFACES
    //
    public static DrawAble PolygonDrawAbleFromMPolygon(MPolygon mpoly, int _dimensionality)
    {
    DrawAble dl = new DrawAble(DrawAbleType.Surface, _dimensionality);
    Point3dCollection p3dColl = new Point3dCollection();
    LoopDirection loopdirection;
    int ords_counter = 0; // The total ordinates in the array
    int hasBulgesCount = 0;
    int loops = mpoly.NumMPolygonLoops;
    for (int i = 0; i < loops; i++)
    {
    // Gather up points and bulges for this loop
    MPolygonLoop mPolygonLoop = mpoly.GetMPolygonLoopAt(i);
    loopdirection = mpoly.GetLoopDirection(i);
    hasBulgesCount = 0;
    ords_counter = 0;
    // Remove duplicate verticies
    for (int d = 1; d < mPolygonLoop.Count - 1; d++)
    {
    if (mPolygonLoop[d].Vertex.IsEqualTo(mPolygonLoop[d + 1].Vertex))
    {
    mPolygonLoop.RemoveAt(d + 1);
    }
    }
    //
    Point3d[] pts = new Point3d[mPolygonLoop.Count];
    double[] blgs = new double[mPolygonLoop.Count];
    for (int z = 0; z < mPolygonLoop.Count; z++)
    {
    if (z == mPolygonLoop.Count - 1)
    {
    pts[z] = pts[0];
    }
    else
    {
    double X = Math.Round(mPolygonLoop[z].Vertex.X, 10, MidpointRounding.AwayFromZero);
    double Y = Math.Round(mPolygonLoop[z].Vertex.Y, 10, MidpointRounding.AwayFromZero);
    double Z = Math.Round(mpoly.Elevation, 10, MidpointRounding.AwayFromZero);
    pts[z] = new Point3d(X, Y, Z);
    }
    blgs[z] = mPolygonLoop[z].Bulge;
    if (blgs[z] != 0.0)
    hasBulgesCount = hasBulgesCount + 1;
    }
    //
    // Suspect code here ......
    //
    if (blgs[0] == blgs[mPolygonLoop.Count - 1] && blgs[0] != 0.0)
    {
    blgs[mPolygonLoop.Count - 1] = 0.0;
    hasBulgesCount--;
    }
    //
    //DO THE STUFF
    //
    DrawAbleSubComponent dlc = new DrawAbleSubComponent();
    TriInts headerElem = new TriInts(ords_counter, 0, 0);
    if (hasBulgesCount == 0)
    {
    headerElem.INTERP = SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine);
    }
    //else if (hasBulgesCount == pts.Length)
    else if (hasBulgesCount == pts.Length - 1)
    {
    headerElem.INTERP = SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves);
    }

    if (loopdirection == LoopDirection.Exterior)
    {
    if (headerElem.INTERP == SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine) ||
    headerElem.INTERP == SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves))
    {
    headerElem.ETYPE = SDO.BasicETYPE(DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine);
    if (headerElem.INTERP == SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine))
    dlc.Etype = DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine;
    else
    dlc.Etype = DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves;
    }
    }
    else
    {

    if (headerElem.INTERP == SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine) ||
    headerElem.INTERP == SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves))
    {
    headerElem.ETYPE = SDO.BasicETYPE(DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine);
    if (headerElem.INTERP == SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine))
    dlc.Etype = DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine;
    else
    dlc.Etype = DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves;
    }
    }
    // If we have not set the etype it must be a 1005 0R 2005 - compound polygon
    if (headerElem.ETYPE == 0 && hasBulgesCount > 0)
    {
    if (loopdirection == LoopDirection.Exterior)
    {
    headerElem.ETYPE = SDO.BasicETYPE(DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine);
    dlc.Etype = DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine;
    }
    else
    {
    headerElem.ETYPE = SDO.BasicETYPE(DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine);
    dlc.Etype = DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine;
    }
    headerElem.INTERP = 0; // to be set later with count
    }
    //Now we are ready to build the elem and ords
    int len = (_dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D) ? DrawAbleSdoGeometry.DefaultDimensionality3D : DrawAbleSdoGeometry.DefaultDimensionality2D;
    dlc.Ords = new decimal[(len * pts.Length) + (hasBulgesCount * len)];
    List elmList = new List();
    TriInts wrkrElm = null;
    int nxtINTERP = 0;
    int lstINTERP = 0;
    Point3d arc_endpoint;
    for (int j = 0; j < pts.Length; j++)
    {
    if (j < pts.Length - 1)
    nxtINTERP = (blgs[j] == 0.0) ? SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleLine) : SDO.BasicINTERPRETATION(DrawAbleSubComponentEType.SimpleLineAllCurves);

    if (lstINTERP != nxtINTERP)
    {
    if (wrkrElm != null)
    elmList.Add(wrkrElm);
    wrkrElm = new TriInts(ords_counter,
    SDO.BasicETYPE((blgs[j] == 0.0) ? DrawAbleSubComponentEType.SimpleLine : DrawAbleSubComponentEType.SimpleLineAllCurves),
    nxtINTERP);
    lstINTERP = nxtINTERP;
    }

    double theBulge = blgs[j];
    if (theBulge != 0.0)
    {
    arc_endpoint = pts[j + 1];
    CircularArc2d ca2d = new CircularArc2d(
    new Point2d(pts[j].X, pts[j].Y),
    new Point2d(arc_endpoint.X, arc_endpoint.Y), theBulge, false);

    Interval interval_of_arc = ca2d.GetInterval();
    Point2d somePointOnArc = ca2d.EvaluatePoint(interval_of_arc.Element / 2);
    //Start
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);
    //Center point on arc
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(somePointOnArc.X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(somePointOnArc.Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);
    }
    else
    {
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].X);
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Y);
    if (len == DrawAbleSdoGeometry.DefaultDimensionality3D)
    dlc.Ords[ords_counter++] = System.Convert.ToDecimal(pts[j].Z);
    }

    }//for loop of ordinates
    int elem_cntr = 0;
    if (headerElem.ETYPE == SDO.BasicETYPE(DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine) ||
    headerElem.ETYPE == SDO.BasicETYPE(DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine))
    {
    //Add our last worker element
    elmList.Add(wrkrElm);
    //Update the count in the header
    headerElem.INTERP = elmList.Count;
    //Dimension the array = element list count + one(1) for header "times" three(3)
    dlc.Elem = new int[(elmList.Count + 1) * 3];
    dlc.Elem[elem_cntr++] = headerElem.OFFSET;
    dlc.Elem[elem_cntr++] = headerElem.ETYPE;
    dlc.Elem[elem_cntr++] = headerElem.INTERP;
    for (int _i = 0; _i < elmList.Count; _i++)
    {
    dlc.Elem[elem_cntr++] = elmList[_i].OFFSET;
    dlc.Elem[elem_cntr++] = elmList[_i].ETYPE;
    dlc.Elem[elem_cntr++] = elmList[_i].INTERP;
    }
    }
    else
    {
    dlc.Elem = new int[3];
    dlc.Elem[elem_cntr++] = headerElem.OFFSET;
    dlc.Elem[elem_cntr++] = headerElem.ETYPE;
    dlc.Elem[elem_cntr++] = headerElem.INTERP;
    }
    dl.SubComponents.Add(dlc);
    }//next ring in the MPolygon

    return dl;
    }
    //
    // Returns: List, DBPoint, Polyline, MPolygon
    //
    public static object DrawAbleDwgObj(DrawAble drawable)
    {
    bool firstPointFlag = false;
    int IncrementFor3d = 0;
    if (drawable.Dimensionality == MDADDrawAbles.DrawAbleSdoGeometry.DefaultDimensionality3D)
    IncrementFor3d = 1;
    MPolygon dbMpoly = null;
    Polyline plineCurves = null;
    Polyline plineCompound = null;
    Polyline plineLine = null;
    DBPoint dbPoint = null;
    List dbPointList = null;

    //Turn the dim elements into triplets for easy use
    List elmsList = null;
    int CountOfComponents = drawable.SubComponents.Count;
    foreach (DrawAbleSubComponent cmp in drawable.SubComponents)
    {
    if (cmp.Elem != null)
    {
    elmsList = new List();
    for (int _i = 0; _i < cmp.Elem.Length; )
    {
    TriInts t = new TriInts(cmp.Elem[_i + 0], cmp.Elem[_i + 1], cmp.Elem[_i + 2]);
    elmsList.Add(t);
    _i = _i + 3;
    }
    }
    else
    elmsList = null;
    //Turn all the decimals into doubles
    double[] ords = new double[cmp.Ords.Length];
    for (int j = 0; j < cmp.Ords.Length; j++)
    ords[j] = System.Convert.ToDouble(cmp.Ords[j]);

    DrawAbleSubComponentEType etype = cmp.Etype;
    firstPointFlag = false;

    //
    //Compound components
    //These require a header and fixup of the components dim element array
    //
    if (cmp.Etype == DrawAbleSubComponentEType.CompoundLine ||
    cmp.Etype == DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine ||
    cmp.Etype == DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine)
    {
    CircularArc2d ca2d;
    Point2d firstPoint2d = new Point2d();
    Point2d begPoint2d = new Point2d();
    Point2d arrowPoint2d, endPoint2d;

    plineCompound = new Polyline();

    //We know what it is because of Etype. We just really need the INTERPs and OFFSETs. Skip to one(1)
    for (int _k = 1; _k < elmsList.Count; )
    {
    TriInts t = elmsList[_k]; int OFFSET = t.OFFSET; int ETYPE = t.ETYPE; int INTERP = t.INTERP;
    int nxtOFFSET = 0;
    if (_k < elmsList.Count - 1)
    nxtOFFSET = elmsList[_k + 1].OFFSET;
    else
    nxtOFFSET = ords.Length;
    for (int x = OFFSET; x < nxtOFFSET; )
    {
    double bulgeValue = 0.0;
    if (firstPointFlag == false) { firstPoint2d = new Point2d(ords[x], ords[x + 1]); firstPointFlag = true; }
    if (INTERP == 2)
    {
    begPoint2d = new Point2d(ords[x++], ords[x++]); x = x + IncrementFor3d;
    //Only if we are not at the end. We ended the line with an arc.
    if (x < nxtOFFSET)
    {
    arrowPoint2d = new Point2d(ords[x++], ords[x++]); x = x + IncrementFor3d;
    endPoint2d = new Point2d(ords[x], ords[x + 1]);
    ca2d = new CircularArc2d(begPoint2d, arrowPoint2d, endPoint2d);
    bulgeValue = GetBulge2d(ca2d);
    ca2d.Dispose();
    }
    plineCompound.AddVertexAt(plineCompound.NumberOfVertices, begPoint2d, bulgeValue, 0, 0);
    if (drawable.Dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    plineCompound.Elevation = ords[x - 1];
    }
    else
    {
    begPoint2d = new Point2d(ords[x++], ords[x++]); x = x + IncrementFor3d;
    plineCompound.AddVertexAt(plineCompound.NumberOfVertices, begPoint2d, 0.0, 0.0, 0.0);
    if (drawable.Dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    plineCompound.Elevation = ords[x - 1];
    }
    }
    _k = _k + 1;
    }
    if (firstPoint2d == begPoint2d)
    plineCompound.Closed = true;

    if (cmp.Etype == DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine ||
    cmp.Etype == DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine)
    {
    if (dbMpoly == null)
    {
    dbMpoly = new MPolygon();
    }
    dbMpoly.AppendLoopFromBoundary(plineCompound, false, 0.005);
    dbMpoly.BalanceTree();
    plineCompound.Dispose();
    plineCompound = null;
    }
    }
    //
    //Point and PointCluster
    //
    if (cmp.Etype == DrawAbleSubComponentEType.Point)
    {
    Point3d p3d;
    if (IncrementFor3d == 1)
    p3d = new Point3d(ords[0], ords[1], ords[2]);
    else
    p3d = new Point3d(ords[0], ords[1], 0.0);
    dbPoint = new DBPoint(p3d);
    }
    else if (cmp.Etype == DrawAbleSubComponentEType.PointCluster)
    {
    Point3d p3d;
    dbPointList = new List();

    for (int _x = 0; _x < ords.Length; )
    {
    if (IncrementFor3d == 1)
    p3d = new Point3d(ords[_x++], ords[_x++], ords[_x++]);
    else
    p3d = new Point3d(ords[_x++], ords[_x++], 0.0);
    dbPoint = new DBPoint(p3d);
    dbPointList.Add(dbPoint);
    }
    }
    //
    //Simple lines
    //
    if (cmp.Etype == DrawAbleSubComponentEType.SimpleLine ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine)
    {
    Point2d begPoint2d = new Point2d();
    Point2d firstPoint2d = new Point2d();
    plineLine = new Polyline();

    for (int _x = 0; _x < ords.Length; )
    {
    if (firstPointFlag == false) { firstPoint2d = new Point2d(ords[0], ords[1]); firstPointFlag = true; }
    begPoint2d = new Point2d(ords[_x++], ords[_x++]); _x = _x + IncrementFor3d;
    plineLine.AddVertexAt(plineLine.NumberOfVertices, begPoint2d, 0.0, 0.0, 0.0);
    if (drawable.Dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    plineLine.Elevation = ords[_x - 1];
    }
    if (firstPoint2d == begPoint2d)
    plineLine.Closed = true;

    if (cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine)
    {
    if (dbMpoly == null)
    {
    dbMpoly = new MPolygon();
    }
    dbMpoly.AppendLoopFromBoundary(plineLine, false, 0.005);
    dbMpoly.BalanceTree();
    plineLine.Dispose();
    plineLine = null;
    }
    }
    //
    //Simple Curves
    //
    if (cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleLineAllCurves)
    {
    CircularArc2d ca2d;
    Point2d begPoint2d = new Point2d();
    Point2d firstPoint2d = new Point2d();
    Point2d arrowPoint2d, endPoint2d;
    plineCurves = new Polyline();
    //We know what it is because of Etype. We just really need the INTERPs and OFFSETs. Skip to one(1)
    for (int _x = 0; _x < ords.Length; )
    {
    if (firstPointFlag == false) { firstPoint2d = new Point2d(ords[0], ords[1]); firstPointFlag = true; }
    begPoint2d = new Point2d(ords[_x++], ords[_x++]); _x = _x + IncrementFor3d;
    double bulgeValue = 0.0;
    if (_x < ords.Length)
    {
    arrowPoint2d = new Point2d(ords[_x++], ords[_x++]); _x = _x + IncrementFor3d;
    endPoint2d = new Point2d(ords[_x], ords[_x + 1]);
    ca2d = new CircularArc2d(begPoint2d, arrowPoint2d, endPoint2d);
    bulgeValue = GetBulge2d(ca2d);
    ca2d.Dispose();
    }
    plineCurves.AddVertexAt(plineCurves.NumberOfVertices, begPoint2d, bulgeValue, 0, 0);
    if (drawable.Dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    plineCurves.Elevation = ords[_x - 1];
    }
    if (firstPoint2d == begPoint2d)
    plineCurves.Closed = true;

    if (cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves)
    {
    if (dbMpoly == null)
    {
    dbMpoly = new MPolygon();
    }
    dbMpoly.AppendLoopFromBoundary(plineCurves, false, 0.005);
    dbMpoly.BalanceTree();
    plineCurves.Dispose();
    plineCurves = null;
    }
    }
    //
    // Circle
    //
    if (cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingCircle ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingCircle)
    {
    Circle circleSurf = null;
    Point2d a = new Point2d(ords[0], ords[1]);
    Point2d b = new Point2d(ords[2 + IncrementFor3d], ords[3 + IncrementFor3d]);
    Point2d c = new Point2d(ords[4 + IncrementFor3d + IncrementFor3d], ords[5 + IncrementFor3d + IncrementFor3d]);
    double A = b.X - a.X;
    double B = b.Y - a.Y;
    double C = c.X - a.X;
    double D = c.Y - a.Y;

    double E = A * (a.X + b.X) + B * (a.Y + b.Y);
    double F = C * (a.X + c.X) + D * (a.Y + c.Y);
    double G = 2.0 * (A * (c.Y - b.Y) - B * (c.X - b.X));

    if (G != 0)
    {
    double pX = (D * E - B * F) / G;
    double pY = (A * F - C * E) / G;

    // r^2 = (a.X - pX) ^ 2.0 + (a.Y - pY) ^ 2.0
    double radiusSqd = Math.Pow((a.X - pX), 2.0) + Math.Pow((a.Y - pY), 2.0);
    double radius = Math.Sqrt(radiusSqd);

    Point3d p3d_center = new Point3d(pX, pY, 0.0);
    circleSurf = new Circle(p3d_center, new Vector3d(0.0, 0.0, 1.0), radius);
    }
    if (dbMpoly == null)
    {
    dbMpoly = new MPolygon();
    }
    dbMpoly.AppendLoopFromBoundary(circleSurf, false, 0.005);
    dbMpoly.BalanceTree();
    circleSurf.Dispose();
    circleSurf = null;
    }
    //
    //Rectangle
    //
    if (cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingRectangle ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingRectangle)
    {
    Polyline plineRect = new Polyline();
    Point2d sw2d = new Point2d(ords[0], ords[1]);
    Point2d se2d = new Point2d(ords[2 + IncrementFor3d], ords[1]);
    Point2d ne2d = new Point2d(ords[2 + IncrementFor3d], ords[3 + IncrementFor3d]);
    Point2d nw2d = new Point2d(ords[0], ords[3 + IncrementFor3d]);
    Point2d closer2d = new Point2d(ords[0], ords[1]);
    plineRect.AddVertexAt(plineRect.NumberOfVertices, sw2d, 0.0, 0.0, 0.0);
    plineRect.AddVertexAt(plineRect.NumberOfVertices, se2d, 0.0, 0.0, 0.0);
    plineRect.AddVertexAt(plineRect.NumberOfVertices, ne2d, 0.0, 0.0, 0.0);
    plineRect.AddVertexAt(plineRect.NumberOfVertices, nw2d, 0.0, 0.0, 0.0);
    plineRect.AddVertexAt(plineRect.NumberOfVertices, closer2d, 0.0, 0.0, 0.0);
    plineRect.Closed = true;
    if (drawable.Dimensionality == DrawAbleSdoGeometry.DefaultDimensionality3D)
    plineRect.Elevation = ords[2];
    if (dbMpoly == null)
    {
    dbMpoly = new MPolygon();
    }
    dbMpoly.AppendLoopFromBoundary(plineRect, false, 0.005);
    dbMpoly.BalanceTree();
    plineRect.Dispose();
    plineRect = null;
    }

    }//Do the next subcomponent
    if (dbMpoly != null)
    return (object)dbMpoly;
    else if (dbPointList != null)
    return (object)dbPointList;
    else if (dbPoint != null)
    return (object)dbPoint;
    else if (plineLine != null)
    return (object)plineLine;
    else if (plineCurves != null)
    return (object)plineCurves;
    else if (plineCompound != null)
    return (object)plineCompound;
    else
    return null;

    }

    public static double GetBulge2d(CircularArc2d ca2d)
    {
    double theBulge = 0.0;
    if (ca2d.IsClockWise == true)
    {
    theBulge = -Math.Tan((ca2d.EndAngle - ca2d.StartAngle) / 4);
    }
    else
    {
    theBulge = Math.Tan((ca2d.EndAngle - ca2d.StartAngle) / 4);
    }
    return theBulge;
    }

    }//eoc DrawAbleDwg
    }//eons
  • Tuesday, November 17, 2009

    (VI) New SDO_GEOMETRY <-> Autodesk Map3d 2010

    Author: Jonio, Dennis

    The next on the list ...
  • Given some “DrawAble(s)” compose a NetSdoGeometry.sdogeometry.
    The method signature:
    public static sdogeometry SdoGeometryFromDrawAble(List _drawables, int _lrs, int _srid)
    If you recall the DrawAble holds the dimensionality so the Measure and the SRID had to be injected somewhere.
    Frankly the simplest of all the methods. Very straight forward implementaion.
    Maybe somewhat unusual here is that I made this a static method within the static utility class.

    Source code (C#):

    public static sdogeometry SdoGeometryFromDrawAble(List _drawables, int _lrs, int _srid)
    {
    sdogeometry rtnval = null;
    List TotElms = new List();
    List TotOrds = new List();
    int CURRENT_OFFSET = 1;
    int CountOfItems = _drawables.Count;
    int CountOfComponents = 0;

    foreach (DrawAble drawable in _drawables)
    {
    CountOfComponents = drawable.SubComponents.Count;
    foreach (DrawAbleSubComponent cmp in drawable.SubComponents)
    {
    TriInts nxt_elem = null;
    //
    //Compound components
    //
    if (cmp.Etype == DrawAbleSubComponentEType.CompoundLine ||
    cmp.Etype == DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine ||
    cmp.Etype == DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine)
    {
    TriInts frst_head = new TriInts(CURRENT_OFFSET, BasicETYPE(cmp.Etype), (cmp.Elem.Length / 3) - 1);
    TotElms.Add(frst_head);
    for (int _k = 3; _k < cmp.Elem.Length; )
    {
    TriInts nxt = new TriInts(CURRENT_OFFSET + cmp.Elem[_k + 0], cmp.Elem[_k + 1], cmp.Elem[_k + 2]);
    TotElms.Add(nxt);
    _k = _k + 3;
    }
    //Copy over the ordinates
    for (int _i = 0; _i < cmp.Ords.Length; _i++)
    TotOrds.Add(cmp.Ords[_i]);

    //We get out of the major loop here ...
    //so we MUST set the CURRENT_OFFSET to the end of the ordinates + start point.
    CURRENT_OFFSET = CURRENT_OFFSET + cmp.Ords.Length;
    continue;
    }
    //
    //Point and PointCluster
    //
    if (cmp.Etype == DrawAbleSubComponentEType.Point)
    {
    nxt_elem = new TriInts(CURRENT_OFFSET, BasicETYPE(cmp.Etype), BasicINTERPRETATION(cmp.Etype));
    TotElms.Add(nxt_elem);
    //Copy over the ordinates
    for (int _i = 0; _i < cmp.Ords.Length; _i++)
    TotOrds.Add(cmp.Ords[_i]);
    CURRENT_OFFSET = CURRENT_OFFSET + cmp.Ords.Length;
    continue;
    }
    else if (cmp.Etype == DrawAbleSubComponentEType.PointCluster)
    {
    nxt_elem = new TriInts(CURRENT_OFFSET, BasicETYPE(cmp.Etype), cmp.Elem[2]);
    TotElms.Add(nxt_elem);
    }
    //
    //Lines
    //
    if (cmp.Etype == DrawAbleSubComponentEType.SimpleLine ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleLineAllCurves)
    {
    nxt_elem = new TriInts(CURRENT_OFFSET, BasicETYPE(cmp.Etype), BasicINTERPRETATION(cmp.Etype));
    TotElms.Add(nxt_elem);
    }
    //
    //Surface Stuff
    //
    if (cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingCircle ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceInnerRingRectangle ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingCircle ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine ||
    cmp.Etype == DrawAbleSubComponentEType.SimpleSurfaceOuterRingRectangle
    )
    {
    nxt_elem = new TriInts(CURRENT_OFFSET, BasicETYPE(cmp.Etype), BasicINTERPRETATION(cmp.Etype));
    TotElms.Add(nxt_elem);
    }

    //Copy over the ordinates and move the CURRENT OFFSET
    for (int _i = 0; _i < cmp.Ords.Length; _i++)
    TotOrds.Add(cmp.Ords[_i]);
    CURRENT_OFFSET = TotOrds.Count + 1;
    }
    }
    //
    // Now build the geometry object
    //
    if (TotElms.Count > 0 && TotOrds.Count > 0)
    {
    DrawAble drawable = _drawables[0];
    decimal[] tmp_elems = new decimal[TotElms.Count * 3];
    for (int _e = 0; _e < TotElms.Count; _e++)
    {
    tmp_elems[_e * 3 + 0] = TotElms[_e].OFFSET;
    tmp_elems[_e * 3 + 1] = TotElms[_e].ETYPE;
    tmp_elems[_e * 3 + 2] = TotElms[_e].INTERP;
    }
    decimal[] tmp_ords = new decimal[TotOrds.Count];
    tmp_ords = TotOrds.ToArray();
    rtnval = new sdogeometry();
    rtnval.LRS = _lrs;
    rtnval.sdo_srid = _srid;
    rtnval.Dimensionality = drawable.Dimensionality;
    rtnval.ElemArray = tmp_elems;
    rtnval.OrdinatesArray = tmp_ords;
    rtnval.GeometryType = InferGeometryType(_drawables);
    rtnval.PropertiesToGTYPE();
    }
    return rtnval;
    }
  • Sunday, November 15, 2009

    (V) New SDO_GEOMETRY <-> Autodesk Map3d 2010

    Author: Jonio, Dennis

    As I stated in the last post:
  • Given a NetSdoGeometry.sdogeometry decompose it into a “DrawAble(s)”.
    As you would suspect this is mostly code. This is the actor that gets invoked every time DrawAbleSdoGeometry gets instantiated via DrawAbleSdoGeometry(sdogeometry aSDO_GEOMETRY) or the Geometry within an existing DrawAbleSdoGeometry gets changed.

    The todo here is to breakdown and pair SDO_ELEM_INFO elements with SDO_ORDINATES elements. The end result will be at least one DrawAble(s).
    Source code (C#):

    private void DrawAblesFromGeometry()
    {
    sdogeometry g = Geometry;
    int[] elms = g.ElemArrayOfInts;
    decimal[] ords = g.OrdinatesArray;
    int dimensions = g.Dimensionality;
    int OFFSET = 0, nxtOFFSET = 0;
    int ETYPE = 0, nxtETYPE = 0;
    int INTERP = 0, nxtINTERP = 0;
    int ETYPE_plus_INTERP = 0;
    //Just to make it easier to work with
    List elmList = new List();
    for (int _i = 0; _i < elms.Length; )
    {
    TriInts tmp_triplet = new TriInts(elms[_i], elms[_i + 1], elms[_i + 2]);
    elmList.Add(tmp_triplet);
    _i = _i + 3;
    }
    //Iterate through the triplets
    for (int _j = 0; _j < elmList.Count; )
    {
    TriInts wrkrElm = elmList[_j];
    OFFSET = wrkrElm.OFFSET;
    ETYPE = wrkrElm.ETYPE;
    INTERP = wrkrElm.INTERP;
    ETYPE_plus_INTERP = ETYPE + INTERP;
    //Look ahead is required for getting and setting offset into the ordinates array
    if (_j < elmList.Count - 1)
    { nxtOFFSET = elmList[_j + 1].OFFSET; nxtETYPE = elmList[_j + 1].ETYPE; nxtINTERP = elmList[_j + 1].INTERP; }
    else
    { nxtOFFSET = nxtETYPE = nxtINTERP = 0; }
    int len_of_ords = 0;
    if (nxtOFFSET > 0)
    {
    len_of_ords = nxtOFFSET - OFFSET;
    }
    else
    {
    len_of_ords = (ords.Length - OFFSET) + 1;
    }
    int len = 0;
    //Based upon the ETYPE and the INTERPRETATION
    switch (ETYPE)
    {
    case 1:
    if (INTERP > 1)
    {
    DrawAble drawp = new DrawAble(DrawAbleType.Point, dimensions);
    DrawAbleSubComponent drawpc = new DrawAbleSubComponent();
    drawpc.Etype = DrawAbleSubComponentEType.PointCluster;
    drawpc.Elem = new int[] { 0, 1, INTERP };
    drawpc.Ords = new decimal[len];
    Array.Copy(ords, OFFSET - 1, drawpc.Ords, 0, len_of_ords);
    drawp.SubComponents.Add(drawpc);
    this.Drawables.Add(drawp);
    }
    else if (INTERP == 1)
    {
    DrawAble drawp1 = new DrawAble(DrawAbleType.Point, dimensions);
    DrawAbleSubComponent drawp1c = new DrawAbleSubComponent();
    drawp1c.Etype = DrawAbleSubComponentEType.Point;
    drawp1c.Ords = new decimal[len_of_ords];
    Array.Copy(ords, OFFSET - 1, drawp1c.Ords, 0, len_of_ords);
    drawp1.SubComponents.Add(drawp1c);
    this.Drawables.Add(drawp1);
    }
    break;
    case 2:
    DrawAble drawl = new DrawAble(DrawAbleType.Line, dimensions);
    DrawAbleSubComponent drawlc = new DrawAbleSubComponent();
    if (ETYPE_plus_INTERP == (int)DrawAbleSubComponentEType.SimpleLine)
    drawlc.Etype = DrawAbleSubComponentEType.SimpleLine;
    else
    drawlc.Etype = DrawAbleSubComponentEType.SimpleLineAllCurves;
    drawlc.Ords = new decimal[len_of_ords];
    Array.Copy(ords, OFFSET - 1, drawlc.Ords, 0, len_of_ords);
    drawl.SubComponents.Add(drawlc);
    this.Drawables.Add(drawl);
    break;
    case 4:
    DrawAble drawcombo = new DrawAble(DrawAbleType.Line, dimensions);
    DrawAbleSubComponent drawcomboc = new DrawAbleSubComponent();
    drawcomboc.Etype = DrawAbleSubComponentEType.CompoundLine;
    int number_of_subelements = INTERP;
    int final_len_of_elms = (number_of_subelements * 3) + 3;
    int first_OFFSET = OFFSET;
    //The subelements PLUS the header
    int[] redone_elms = new int[final_len_of_elms];
    int redone_n = 0;
    redone_elms[redone_n++] = OFFSET - first_OFFSET;
    redone_elms[redone_n++] = ETYPE;
    redone_elms[redone_n++] = INTERP;
    _j = _j + 1;
    for (int k = 1; k <= number_of_subelements; )
    {
    OFFSET = elmList[_j].OFFSET;
    ETYPE = elmList[_j].ETYPE;
    INTERP = elmList[_j].INTERP;

    redone_elms[redone_n + 0] = OFFSET - first_OFFSET;
    redone_elms[redone_n + 1] = ETYPE;
    redone_elms[redone_n + 2] = INTERP;
    redone_n = redone_n + 3;
    k = k + 1;
    _j = _j + 1;
    }
    // _j is now pointing past this "4" string and we MAY be looking at another drawable
    // We find out by comparing the redone_elms count w/elmList count.
    if ((number_of_subelements + 1) < elmList.Count)
    {
    len_of_ords = elmList[_j].OFFSET - first_OFFSET;
    //We now decrement _j because we did not consume the entire thing.
    _j = _j - 1;
    }
    else
    len_of_ords = (ords.Length - first_OFFSET) + 1;

    drawcomboc.Ords = new decimal[len_of_ords];
    Array.Copy(ords, first_OFFSET - 1, drawcomboc.Ords, 0, len_of_ords);
    //Copy the elms
    drawcomboc.Elem = new int[(number_of_subelements * 3) + 3];
    Array.Copy(redone_elms, 0, drawcomboc.Elem, 0, (number_of_subelements * 3) + 3);
    //Add the component to the drawable
    drawcombo.SubComponents.Add(drawcomboc);
    //Add the drawable
    this.Drawables.Add(drawcombo);
    break;
    case 1003:
    DrawAble drawsurf1003 = new DrawAble(DrawAbleType.Surface, dimensions);
    DrawAbleSubComponent drawsurfc1003 = new DrawAbleSubComponent();
    switch (ETYPE_plus_INTERP)
    {
    case (int)DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine:
    drawsurfc1003.Etype = DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine;
    break;
    case (int)DrawAbleSubComponentEType.SimpleSurfaceOuterRingCircle:
    drawsurfc1003.Etype = DrawAbleSubComponentEType.SimpleSurfaceOuterRingCircle;
    break;
    case (int)DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves:
    drawsurfc1003.Etype = DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves;
    break;
    case (int)DrawAbleSubComponentEType.SimpleSurfaceOuterRingRectangle:
    drawsurfc1003.Etype = DrawAbleSubComponentEType.SimpleSurfaceOuterRingRectangle;
    break;
    default:
    break;
    }
    if (nxtOFFSET == 0)
    len = ords.Length - OFFSET + 1;
    else
    len = Math.Abs(nxtOFFSET - OFFSET);
    drawsurfc1003.Ords = new decimal[len];
    Array.Copy(ords, OFFSET - 1, drawsurfc1003.Ords, 0, len_of_ords);
    drawsurf1003.SubComponents.Add(drawsurfc1003);
    this.Drawables.Add(drawsurf1003);
    break;
    case 2003:
    DrawAbleSubComponent drawsurfc2003 = new DrawAbleSubComponent();
    switch (ETYPE_plus_INTERP)
    {
    case (int)DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine:
    drawsurfc2003.Etype = DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine;
    break;
    case (int)DrawAbleSubComponentEType.SimpleSurfaceInnerRingCircle:
    drawsurfc2003.Etype = DrawAbleSubComponentEType.SimpleSurfaceInnerRingCircle;
    break;
    case (int)DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves:
    drawsurfc2003.Etype = DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves;
    break;
    case (int)DrawAbleSubComponentEType.SimpleSurfaceInnerRingRectangle:
    drawsurfc2003.Etype = DrawAbleSubComponentEType.SimpleSurfaceInnerRingRectangle;
    break;
    default:
    break;
    }
    if (nxtOFFSET == 0)
    len = ords.Length - OFFSET + 1;
    else
    len = Math.Abs(nxtOFFSET - OFFSET);
    drawsurfc2003.Ords = new decimal[len];
    Array.Copy(ords, OFFSET - 1, drawsurfc2003.Ords, 0, len_of_ords);
    bool hasHome = false;
    for (int _i = this.Drawables.Count - 1; _i >= 0; _i--)
    {
    if (Drawables[_i].DrawEtype == DrawAbleType.Surface)
    {
    Drawables[_i].SubComponents.Add(drawsurfc2003);
    hasHome = true;
    break;
    }
    }
    if (hasHome == false)
    OrphanComponents.Add(drawsurfc2003);
    break;
    case 1005:
    case 2005:
    DrawAble drawsurfX005 = new DrawAble(DrawAbleType.Surface, dimensions);
    DrawAbleSubComponent drawsurfcX005 = new DrawAbleSubComponent();
    if (ETYPE == 1005)
    drawsurfcX005.Etype = DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine;
    else
    drawsurfcX005.Etype = DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine;
    number_of_subelements = INTERP;
    final_len_of_elms = (number_of_subelements * 3) + 3;
    first_OFFSET = OFFSET;
    //The subelements PLUS the header
    redone_elms = new int[final_len_of_elms];
    redone_n = 0;
    redone_elms[redone_n++] = OFFSET - first_OFFSET;
    redone_elms[redone_n++] = ETYPE;
    redone_elms[redone_n++] = INTERP;
    _j = _j + 1;
    for (int k = 1; k <= number_of_subelements; )
    {
    OFFSET = elmList[_j].OFFSET;
    ETYPE = elmList[_j].ETYPE;
    INTERP = elmList[_j].INTERP;

    redone_elms[redone_n + 0] = OFFSET - first_OFFSET;
    redone_elms[redone_n + 1] = ETYPE;
    redone_elms[redone_n + 2] = INTERP;
    redone_n = redone_n + 3;
    k = k + 1;
    _j = _j + 1;
    }
    //We must remember to decrement _j because we may not have consumed the entire thing.
    if ((number_of_subelements + 1) < elmList.Count)
    {
    len_of_ords = elmList[_j].OFFSET - first_OFFSET;
    }
    else
    len_of_ords = (ords.Length - first_OFFSET) + 1;

    drawsurfcX005.Ords = new decimal[len_of_ords];
    Array.Copy(ords, first_OFFSET - 1, drawsurfcX005.Ords, 0, len_of_ords);
    //Copy the elms
    drawsurfcX005.Elem = new int[(number_of_subelements * 3) + 3];
    Array.Copy(redone_elms, 0, drawsurfcX005.Elem, 0, (number_of_subelements * 3) + 3);
    //Add the drawable if it is a 1005
    if (drawsurfcX005.Etype == DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine)
    {
    //Add the component to the drawable
    drawsurfX005.SubComponents.Add(drawsurfcX005);
    this.Drawables.Add(drawsurfX005);
    }
    else
    {
    // This is a 2005 and it needs the "nearest" outer ring to live within
    hasHome = false;
    for (int _i = this.Drawables.Count - 1; _i >= 0; _i--)
    {
    if (Drawables[_i].DrawEtype == DrawAbleType.Surface)
    {
    Drawables[_i].SubComponents.Add(drawsurfcX005);
    hasHome = true;
    break;
    }
    }
    if (hasHome == false)
    OrphanComponents.Add(drawsurfcX005);
    }
    //We moved _j ahead ONE(1) to far ... in persuit of the nxtOFFSET.
    //We must decrement it so we land back at real next "header" triplet
    _j = _j - 1;
    break;
    default:
    break;
    }
    _j = _j + 1;
    }// main for loop
    }
  • Friday, November 13, 2009

    (IV) New SDO_GEOMETRY <-> Autodesk Map3d 2010

    Author: Jonio, Dennis

    Before I begin to discuss additional detail I will briefly illustrate what it looks like to materialize an Autodesk/Map3d object from a NetSdoGeometry.sdogeometry with this approach. The other class DrawAbleDwg shown below has not been discussed at all to this point. This is in fact the simplest pattern that can be used when dealing with the MULTI type.
    Source code (C#):

    using MDADDrawAbles;
    using MDADDrawAbleDwg;
    using DDwg = MDADDrawAbleDwg.DrawAbleDwg;

    DrawAbleSdoGeometry D_sdo = new DrawAbleSdoGeometry(some_sdogeometry);
    foreach (DrawAble d in D_sdo.Drawables)
    {
    object aObj = DDwg.DrawAbleDwgObj(d);

    if (aObj is Autodesk.AutoCAD.DatabaseServices.MPolygon)
    {
    DDwg.AddMPolygon(aObj as MPolygon, 5, "MPolygon", "a polygon");
    }
    else if (aObj is Autodesk.AutoCAD.DatabaseServices.Polyline)
    {
    DDwg.AddPline(aObj as Polyline, 6, "Polyline", "a polyline");
    }
    else if (aObj is Autodesk.AutoCAD.DatabaseServices.DBPoint)
    {
    DDwg.AddPointd(aObj as DBPoint, 4, "Point", "a point");
    }
    }

    The following illustrates just the opposite, a NetSdoGeometry.sdogeometry from multiple Autodesk/Map3d objects. The three(3) in this case will capture the Z axis. Actually I don't know what I am going to do with it but I have it if it is necessary.
    Source code (C#):

    DrawAble d3 = null;
    PromptSelectionOptions pso = new PromptSelectionOptions();
    pso.MessageForAdding = "\nEntities must be MPolygons, Polylines, Arc, Circles or Points.";
    pso.AllowDuplicates = false;
    pso.AllowSubSelections = false;
    pso.SingleOnly = false;

    PromptSelectionResult psr = ed.GetSelection(pso, MakeFilter());
    if (psr.Status == PromptStatus.OK)
    {
    List drawList = new List();

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
    foreach (SelectedObject seleobj in psr.Value)
    {
    Entity ent;
    Entity entdb = (Entity)tr.GetObject(seleobj.ObjectId, OpenMode.ForRead);
    //Other stuff
    ent = entdb;
    Polyline pl = ent as Polyline;
    Polyline2d pl2d = ent as Polyline2d;
    Polyline3d pl3d = ent as Polyline3d;
    Arc anArc = ent as Arc;
    DBPoint dbPoint = ent as DBPoint;
    MPolygon mpoly = ent as MPolygon;
    Line line = ent as Line;
    Circle circ = ent as Circle;
    if (line == null && pl == null && pl2d == null && pl3d == null && anArc == null
    && dbPoint == null && mpoly == null && circ == null)
    {
    }
    else
    {

    if (pl != null)
    {
    d3 = DDwg.LineCurveDrawAbleFromPolyline(pl, null, null, 3);
    }
    if (pl2d != null)
    {
    d3 = DDwg.LineCurveDrawAbleFromPolyline(null, pl2d, null, 3);
    }
    if (pl3d != null)
    {
    d3 = DDwg.LineCurveDrawAbleFromPolyline(null, null, pl3d, 3);
    }
    if (mpoly != null)
    {
    d3 = DDwg.PolygonDrawAbleFromMPolygon(mpoly, 3);
    }
    if (anArc != null)
    {
    d3 = DDwg.LineCurveDrawAbleFromArc(anArc, 3);
    }
    if (line != null)
    {
    d3 = DDwg.LineCurveDrawAbleFromLine(line, 3);
    }
    if (dbPoint != null)
    {
    d3 = DDwg.PointDrawAbleFromPoint(dbPoint, 3);
    }
    if (circ != null)
    {
    d3 = DDwg.LineCurveDrawAbleFromCircle(circ, 3);
    }

    }
    drawList.Add(d3);
    }//foreach object in the selection set
    }//using transaction

    sdogeometry geometry = DrawAbleSdoGeometryUtil.SdoGeometryFromDrawAble(drawList, 0, 2236);

    }//prompt stat OK

    DrawAbleSdoGeometryUtil.SdoGeometryFromDrawAble(drawList, 0, 2236); Passing in the DrawAble, the LRS, and the SRID produces a sdogeometry!

    Here is the list of things that remain to be shown:
  • Given a NetSdoGeometry.sdogeometry decompose it into a “DrawAble(s)”.
  • Given some “DrawAble(s)” compose a NetSdoGeometry.sdogeometry.
  • Given one or more Autodesk/Map3d objects decompose it(them) into “Drawable(s)”.
  • Given a “DrawAble” compose a Autodesk/Map3d object.
    To be continued ...
  •