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 ...
  • Thursday, November 12, 2009

    (III) New SDO_GEOMETRY <-> Autodesk Map3d 2010

    Author: Jonio, Dennis

    Before I forget I did put together a simple class to aid in manipulating the three(3) element array structures that comprise SDO_ELEM_INFO_ARRAY.
    Source code (C#):

    [Serializable]
    public class TriInts
    {
    public int OFFSET
    { set { TriInt[0] = value; } get { return TriInt[0]; } }
    public int ETYPE
    { set { TriInt[1] = value; } get { return TriInt[1]; } }
    public int INTERP
    { set { TriInt[2] = value; } get { return TriInt[2]; } }
    private int[] TriInt;

    public TriInts()
    {
    TriInt = new int[] { 0, 0, 0 };
    }
    public TriInts(int o, int e, int i)
    {
    TriInt = new int[3];
    TriInt[0] = o;
    TriInt[1] = e;
    TriInt[2] = i;
    }
    public TriInts(TriInts triint)
    {
    TriInt = new int[3];
    TriInt[0] = triint.OFFSET;
    TriInt[1] = triint.ETYPE;
    TriInt[2] = triint.INTERP;
    }
    public int[] ToArray()
    {
    return new int[] { OFFSET, ETYPE, INTERP };
    }
    }//eoc TriInts

    So now we get to the primary actor DrawAbleSdoGeometry. The container class for the NetSdoGeometry.sdogeometry type and the supporting cast of players to break sdogeometry down into DrawAble(s) and build a sdogeometry from DrawAble(s). Again the paradigm is all about this intermediate drawable construct so Autodesk/Map3d doesn’t come into play here. That is all handled in a separate class!
    Source code (C#):

    [Serializable]
    public class DrawAbleSdoGeometry
    {
    private sdogeometry m_Geometry;
    public const decimal DefaultSRID2236 = 2236;
    public const int DefaultLRS0 = 0;
    public const int DefaultDimensionality2D = 2;
    public const int DefaultDimensionality3D = 3;
    public decimal SRID = DefaultSRID2236;
    public int LRS = DefaultLRS0;
    public int Dimensionality = DefaultDimensionality2D;
    public List Drawables = new List();
    public List OrphanComponents = new List();
    // Default ctor - nothing to do
    public DrawAbleSdoGeometry() { }
    // ctor from an existing SDO_GEOMETRY object
    public DrawAbleSdoGeometry(sdogeometry aGeometry)
    {
    this.Geometry = aGeometry;
    }
    }//eoc DrawAbleSdoGeometry


    I set a default Dimensionality, LRS and SRID but have left them totally accessible. I am not one to hide things away in some private corner somewhere unless it just is nonsensical to do otherwise. Like DrawAblesFromGeometry(), the player that decomposes a sdogeometry/SDO_GEOMETRY object into DrawAble(s). It only made sense to me to invoke this directly from the “setter” for the class’ Geometry object.
    Note also that within the “setter” I deal with that Optimized Point issue.
    Source code (C#):

    public sdogeometry Geometry
    {
    get { return this.m_Geometry; }

    set
    {
    m_Geometry = value;
    try
    {
    m_Geometry.PropertiesFromGTYPE();
    Dimensionality = m_Geometry.Dimensionality;

    if (m_Geometry.sdo_point != null)
    {
    m_Geometry.ElemArray = new decimal[] { 1, 1, 1 };
    if (m_Geometry.Dimensionality == 2)
    m_Geometry.OrdinatesArray = new decimal[] { (decimal)m_Geometry.sdo_point.X, (decimal)m_Geometry.sdo_point.Y };
    else if (m_Geometry.Dimensionality == 3)
    m_Geometry.OrdinatesArray = new decimal[] { (decimal)m_Geometry.sdo_point.X, (decimal)m_Geometry.sdo_point.Y, (decimal)m_Geometry.sdo_point.Z };
    m_Geometry.sdo_point = null;
    }
    if (m_Geometry.ElemArray != null && m_Geometry.OrdinatesArray != null)
    DrawAblesFromGeometry();
    }
    catch (System.Exception) {/*Just eat it all*/}
    }
    }

    As regards catching and eating any errors at this level I am ambivilant. I really do assume VALID geometry coming in because I produce VALID geometry on the other end. You may see it differently.

    To be continued …

    (II) New SDO_GEOMETRY <-> Autodesk Map3d 2010

    Author: Jonio, Dennis

    The DrawAbleType enums were easy. I just had to give them values that could be distinguised via “OR”ing them together.

  • Point = 1,
  • Line = 2,
  • Surface = 4


    Source code (C#):

    public static int InferGeometryType(List _drawables)
    {
    int rtnval = 0;
    if (_drawables.Count == 1)
    {
    switch (_drawables[0].DrawEtype)
    {
    case DrawAbleType.Point:
    rtnval = 1;
    break;
    case DrawAbleType.Line:
    rtnval = 2;
    break;
    case DrawAbleType.Surface:
    rtnval = 3;
    break;
    }
    }
    else
    {
    int ttype = 0;
    foreach (DrawAble d in _drawables)
    ttype = ttype | (int)d.DrawEtype;

    switch (ttype)
    {
    case 1:
    rtnval = 5; //MultiPoint
    break;
    case 2:
    rtnval = 6; //MultiLine
    break;
    case 4:
    rtnval = 7; //MultiPolygon
    break;
    default:
    rtnval = 4; //Collection
    break;
    }
    }
    return rtnval;
    }

    I really wrestled with these DrawAbleSubComponentEType enums. I tried to be really clever with these values and somehow take advantage of the relationship between ETYPE and INTERPRETATION. Tried is the operative word.

  • Point = 1, //1
  • PointCluster = 10, //1 + n
  • PointOriented = 19, //Not supported OrientedPoint
  • SimpleLine = 3, //2 + 1
  • SimpleLineAllCurves = 4, //2 + 2
  • CompoundLine = 40, //4 + n
  • SimpleSurfaceOuterRingLine = 1004, //1003 + 1
  • SimpleSurfaceOuterRingAllCurves = 1005, //1003 + 2
  • SimpleSurfaceOuterRingRectangle = 1006, //1003 + 3
  • SimpleSurfaceOuterRingCircle = 1007, //1003 + 4
  • SimpleSurfaceInnerRingLine = 2004, //2003 + 1
  • SimpleSurfaceInnerRingAllCurves = 2005, //2003 + 2
  • SimpleSurfaceInnerRingRectangle = 2006, //2003 + 3
  • SimpleSurfaceInnerRingCircle = 2007, //2003 + 4
  • CompoundSurfaceOuterRingLine = 10050, //1005 + n
  • CompoundSurfaceInnerRingLine = 20050 //2005 + n
    The specification has to many exceptions for this to work but at least I have my unique values.


    I do wonder alot as to why Oracle set up the unique combinations for Circle, Rectangle and instances of all Curves. I did read the spec on “Oriented Point” and just arbitrarily decided NOT to support it. I will never use it and I guess I am the boss. So if you need that you will have to do it yourself. It should be a straight forward job for someone with the motivation.


    When it gets time to resolve these into the “real” ETYPE and INTERPRETATION values I just set up a couple static methods in a static utility class.
    Source code (C#):

    public static int BasicETYPE(DrawAbleSubComponentEType t)
    {
    int rtnval = 0;
    switch (t)
    {
    case DrawAbleSubComponentEType.Point:
    case DrawAbleSubComponentEType.PointCluster:
    case DrawAbleSubComponentEType.PointOriented:
    rtnval = 1;
    break;
    case DrawAbleSubComponentEType.SimpleLine:
    case DrawAbleSubComponentEType.SimpleLineAllCurves:
    rtnval = 2;
    break;
    case DrawAbleSubComponentEType.CompoundLine:
    rtnval = 4;
    break;
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine:
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves:
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingCircle:
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingRectangle:
    rtnval = 1003;
    break;
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine:
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves:
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingCircle:
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingRectangle:
    rtnval = 2003;
    break;
    case DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine:
    rtnval = 1005;
    break;
    case DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine:
    rtnval = 2005;
    break;
    default:
    break;
    }
    return rtnval;
    }
    public static int BasicINTERPRETATION(DrawAbleSubComponentEType t)
    {
    int rtnval = 0;
    switch (t)
    {
    case DrawAbleSubComponentEType.Point:
    case DrawAbleSubComponentEType.SimpleLine:
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingLine:
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingLine:
    rtnval = 1;
    break;
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingAllCurves:
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingAllCurves:
    case DrawAbleSubComponentEType.SimpleLineAllCurves:
    rtnval = 2;
    break;
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingRectangle:
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingRectangle:
    rtnval = 3;
    break;
    case DrawAbleSubComponentEType.SimpleSurfaceInnerRingCircle:
    case DrawAbleSubComponentEType.SimpleSurfaceOuterRingCircle:
    rtnval = 4;
    break;
    case DrawAbleSubComponentEType.PointCluster:
    case DrawAbleSubComponentEType.CompoundLine:
    case DrawAbleSubComponentEType.CompoundSurfaceOuterRingLine:
    case DrawAbleSubComponentEType.CompoundSurfaceInnerRingLine:
    rtnval = 0;
    break;
    case DrawAbleSubComponentEType.PointOriented:
    rtnval = 9;
    break;
    default:
    break;
    }
    return rtnval;
    }

    To be continued ...
  • Monday, November 9, 2009

    (I) New SDO_GEOMETRY <-> Autodesk Map3d 2010

    Author: Jonio, Dennis


    Howdy all.
    Well, it has really been awhile since that last post. By the way, I have no idea what happened to Maksim Sestic. Anyone willing to let me know?

    Anyway a lot has transpired over the months not the least of which is that some time ago I built a shiny new Autodesk 2010/Map3d <-> SDO_GEOMETRY translator.

    The learning example I have posted here was/is OK and served its purpose. However, like most software it had to be fixed and/or enhanced (and in this case just thrown away!)
    The new converter supports everything that is in keeping with the Oracle Locator’s - Right To Use license. Obviously then there is no 3D object support. Curves are still fully supported and now ALL of the MULT types are supported. I do include support for the Z axis in this generation. In order to support the MULTI types I forced myself into building some “intermediate” objects. This also lays some of the groundwork for a different geometry object generator in the future. No, we are not having any problems or issues with Autodesk but maybe something else will come along. My NetSdoGeometry.sdogeometry object had to be tweaked a little so that it fully supported the Z axis. Beyond that it is good to go.


    Three(3) primary objectives drove this iteration of the translator.
    I) I wished to support a Z axis value
    II) I wished to support the Oracle MULTI types
    III) A more flexible overall design in general.
    I had to modify my sdogeometry AsText property/ToString method to support the Z axis. If you recall I go out of my way to NOT utilize the "optimized point". I am sure it is a fine thing. For me, logically and programmatically, it is more trouble than its worth. In my way of thinking there is nothing wrong with an SDO_ELEM_INFO_ARRAY(1,1,1) and it is somewhat more consistent with the rest of the standard. I do of course read them in but I never output a SDO_POINT.
    Source code (C#):

    public string AsText
    {
    get
    {
    StringBuilder sb = new StringBuilder();
    sb.Append("MDSYS.SDO_GEOMETRY(");
    sb.Append((sdo_gtype != null) ? sdo_gtype.ToString() : "null");
    sb.Append(",");
    sb.Append((sdo_srid != null) ? sdo_srid.ToString() : "null");
    sb.Append(",");
    // begin point
    if (sdo_point != null)
    {
    sb.Append("MDSYS.SDO_POINT_TYPE(");
    string _tmp = string.Format("{0:0.0#####},{1:0.0#####}{2}{3:#.######}",
    sdo_point.X,
    sdo_point.Y,
    (sdo_point.Z == null) ? null : ",",
    sdo_point.Z);

    sb.Append(_tmp.Trim());
    sb.Append(")");
    }
    else
    {
    sb.Append("null");
    }
    sb.Append(",");
    // begin element array
    if (elemArray != null)
    {
    sb.Append("MDSYS.SDO_ELEM_INFO_ARRAY(");
    for (int i = 0; i < elemArray.Length; i++)
    {
    string _tmp = string.Format("{0}", elemArray[i]);
    sb.Append(_tmp);
    if (i < (elemArray.Length - 1))
    sb.Append(",");
    }
    sb.Append(")");
    }
    else
    {
    sb.Append("null");
    }
    sb.Append(",");
    // begin ordinates array
    if (ordinatesArray != null)
    {
    sb.Append("MDSYS.SDO_ORDINATE_ARRAY(");
    for (int i = 0; i < ordinatesArray.Length; i++)
    {
    string _tmp = string.Format("{0:0.0######}", ordinatesArray[i]);
    sb.Append(_tmp);
    if (i < (ordinatesArray.Length - 1))
    sb.Append(",");
    }
    sb.Append(")");
    }
    else
    {
    sb.Append("null");
    }
    sb.Append(")");
    return sb.ToString();
    }
    }
    public override string ToString()
    {
    return this.AsText;
    }


    Here is the conceptual paradigm that I chose for this iteration:
    An Autodesk drawable entity decomposes into one or more SDO_ELEM_INFO_ARRAY triplet(s) with corresponding ordinates. An Autodesk drawable entity may be composed of one or more SDO_ELEM_INFO_ARRAY triplet(s) with corresponding ordinates.
    With this mental shift from my original tool which is based upon a one-to-one/entity-to-sdogeometry relationship things flowed pretty well. Frankly this was a necessary shift in thinking to support the MULTI types.
    So a class "DrawAble" is composed of "DrawAbleSubComponent"(s) and DrawAbleSubComponents equate to SDO_ELEM_INFO_ARRAY triplet(s) and their corresponding ordinates.
    Source code (C#):

    [Serializable]
    public class DrawAbleSubComponent
    {
    public int[] Elem;
    public decimal[] Ords;
    public DrawAbleSubComponentEType Etype;
    }//eoc DrawAbleSubComponent

    [Serializable]
    public class DrawAble
    {
    private DrawAbleType m_drawtype;
    public DrawAbleType DrawEtype
    { get{return m_drawtype;} set { m_drawtype = value; }}

    private int m_dimensionality = 2;
    public int Dimensionality
    { get { return m_dimensionality; } set { m_dimensionality = value; } }

    public List SubComponents = new List();
    public DrawAble(DrawAbleType _type, int _dimensionality)
    {
    DrawEtype = _type;
    Dimensionality = _dimensionality;
    }
    }//eoc DrawAble

    To be continued ...