Author Topic: drawing temp graphics  (Read 9368 times)

0 Members and 1 Guest are viewing this topic.

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
drawing temp graphics
« on: October 29, 2009, 12:24:26 PM »
I used to use GRDRAW in lisp to display temp graphics, but am trying to switch to pointmonitor or jig usage because they allow you to create an entity, then show it.
With GRDRAW, you can only draw lines, which means breaking down anything you want to draw into line segments.
I actually did this for the romansx font in lisp so I could draw temp text.

Now, GRDRAW shows things and does not clean them from the screen.  Only a redraw or zoom or re-grdrawing them in black will get rid of them.

That is desirable behavior because I tend to highlight info at the start of commands, then update that info as certain things change.

It seems that both pointmonitor and jig methods clear their graphics automatically.  Is there a way to get them not to?
I know I can use ed.DrawVector(...) instead of grdraw pinvoke, that is how i am doing it currently.
thx


James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #1 on: October 29, 2009, 12:27:04 PM »
just noticed the autodelete prop of geometry object, will try setting that to false.
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #2 on: October 29, 2009, 12:29:20 PM »
whoops, autodelete relates to disposable wrapper, not graphics...
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #3 on: October 29, 2009, 12:45:01 PM »
another thing, just doing grdraw or drawvectors is actually really fast.  You can do 10000 lines in an instant.
Its the calcs required to break down arcs and text into lines that slows things down.
In my lisp functions, i even checked if the item to be drawn was in the view, so I could narrow down what really needed to be drawn.
Drawing a normal entity is much more desirable than all the beakdown...
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #4 on: October 30, 2009, 01:46:59 PM »
I looked into the TransientManager object available in 2009, after reading a post from Kean:
http://through-the-interface.typepad.com/through_the_interface/2009/01/selecting-the-nearest-face-of-an-autocad-solid-using-net.html

I put together this test prog:

Code: [Select]
namespace ProgTestingAcad
{
  public class Program
  {

    List<Drawable> _drawn = new List<Drawable>();
   
    [Autodesk.AutoCAD.Runtime.CommandMethod("QQQ")]
    public void TestTransients()
    {
      Document doc = AcAp.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;
      TransientManager tm = TransientManager.CurrentTransientManager;
      IntegerCollection ic = new IntegerCollection();
      foreach (Drawable d in _drawn) {
        tm.EraseTransient(d, ic);
      }
      _drawn.Clear();
      using (Transaction tr = db.TransactionManager.StartTransaction()) {
        Drawable d;
        for (int i = 0; i < 1000; i++) {
          d = (Drawable)new AcDb.Line(new Point3d(0.0, 0.0, 0.0), new Point3d(10.0, 10.0 + (double)i, 0.0));
          tm.AddTransient(
            d,
            TransientDrawingMode.DirectTopmost,
            0,
            ic
          );
          _drawn.Add(d);
        }
        tr.Commit();
      }
    }
  }
}

It runs fine, but if you regen, things move around.  Its really nice though because a regen does not erase the ents.  You have full control over erasing them.  I need to optimize this though for speed, as it seems to matter where the drawable item d is created, and see if it works with text.



James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #5 on: November 02, 2009, 04:11:44 PM »
it does work with text!  not too many responses here, but I believe this completely takes the place of grdraw.
You do have to have 2009 (maybe pinvoke on older) but its the only way to get "fake" entities drawn that do not go away like with pointmonitors and jigs.

Note that the text attachment point did not work here, its still left justified...
Code: [Select]
List<Drawable> _drawn = new List<Drawable>();

    public void TestTransient()
    {
      Document doc = AcAp.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;
      TransientManager tm = TransientManager.CurrentTransientManager;
      IntegerCollection ic = new IntegerCollection();
      foreach (Drawable d in _drawn) {
        tm.EraseTransient(d, ic);
      }
      _drawn.Clear();
      using (Transaction tr = db.TransactionManager.StartTransaction()) {
        AcDb.DBText text = new DBText();
        text.TextString = "james";
        text.ColorIndex = 3;
        text.Justify = AttachmentPoint.MiddleCenter;
        text.Position = new Point3d(0.0, 0.0, 0.0);
        Drawable d;
        d = (Drawable)text;
          tm.AddTransient(
            d,
            TransientDrawingMode.DirectShortTerm,
            0,
            ic
          );
          _drawn.Add(d);
        tr.Commit();
        text.Dispose();
      }
    }
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #6 on: November 02, 2009, 05:52:22 PM »
ok, I must have the record for longest conversation with myself, but I went back to test the speed of this transientgraphics api, and its too fast.  I ran a loop to draw 100000 items and it took less than a second.
That is as fast as i need it, especially since I don't have to break down text and arcs.
That puts the nail in the coffin for grdraw.

Now i just need to better understand what coord system the items reference.  They act ok until you regen, then they move around.
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #7 on: November 02, 2009, 08:14:47 PM »
post++
ok, now i realize its not so cool to put the dispose after the tr.Commit();

that messes up the _drawn list.
But if I remove it, things slow down a bit on add, and really slow down on erase when i go to clean them away.
So I'm not sure how to deal with that.

I realized my confusion on the regen moving things.  You must run update after the view changes.  No big deal if within a command, but I don;t like reactors hanging out watching for regens or view changes.  I think they cause crashes when certain add-ons are running.
James Maeding

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8795
  • AKA Daniel
Re: drawing temp graphics
« Reply #8 on: November 02, 2009, 09:15:53 PM »
I'm not sure how it works in .net, but in the ARX sample (AsdkTransientGraphics) the entity is explicitly deleted after the entity is erased from the TransientManager.
you may need to do something like this...

Code: [Select]
foreach (Drawable d in _drawn)
   {
    tm.EraseTransient(d, ic);
    d.Dispose(); //
   }

to avoid memory leaks


jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #9 on: November 03, 2009, 11:55:20 AM »
yep, you nailed it.
Once I added that, the speed is consistent.
I am able to draw about 20,000 transients a second and erase in same time.

I really need to get on the Bricscad testing, I'm hoping all this .net can be used on that platform.
I'm specifically separating part of my progs that rely on acad namespaces so i can switch and fork the code for each.
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #10 on: November 03, 2009, 01:30:04 PM »
boy, I cannot get dbtext to properly justify.
I tried placing code in different order but it always puts text at 0,0 insertion.
I read about using position prop for certain justification types, so tried using it.
No luck.  Can anyone spot an issue with this:
Code: [Select]
List<Drawable> _drawn = new List<Drawable>();

    public void TestDTextTransient()
    {
      Document doc = AcAp.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;
      TransientManager tm = TransientManager.CurrentTransientManager;
      IntegerCollection ic = new IntegerCollection();
      int vpn = System.Convert.ToInt32(AcAp.GetSystemVariable("CVPORT"));
      ic.Add(vpn);
      //erase
      foreach (Drawable d1 in _drawn) {
        tm.EraseTransient(d1, ic);
        d1.Dispose();
      }
      _drawn.Clear();
      using (Transaction tr = db.TransactionManager.StartTransaction()) {
        Drawable d;
        AcDb.DBText text = new DBText();
        ObjectId styID = HATB.GetTextStyleObjectId("aerial");
        for (int i = 0; i < 10000; i++) {
          text = new DBText();
          text.TextStyle = styID;
          text.TextString = "james";
          text.ColorIndex = 3;
          text.HorizontalMode = TextHorizontalMode.TextCenter;
          text.VerticalMode = TextVerticalMode.TextVerticalMid;
          text.AlignmentPoint = new Point3d(0.0 + (double)i, 0.0 + (double)i * 2, 0.0);
          d = (Drawable)text;
          tm.AddTransient(
            d,
            TransientDrawingMode.DirectShortTerm,
            0,
            ic
          );
          _drawn.Add(d);
        }
        tr.Commit();
        text.Dispose();
      }
    }
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: drawing temp graphics
« Reply #11 on: November 03, 2009, 06:50:03 PM »
this is becoming my own blog site - eh?
ok, after a couple hours of many tests, I figured out the disposal of objects used to make the drawables must be handled carefully.
Since you will always be tracking the drawables in some list, to use for erase later, you must not dispose of the line, arc, mtext or whatever, until you set it to a new object, like this:
(note that I also added the viewport stuff so it only affects current one)
Code: [Select]
public static bool TrDrawLines(List<double[]> pts, int color, bool highlight, out List<Drawable> lstDraws)
    {
      lstDraws = null;
      Document doc = AcAp.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;
      TransientManager tm = TransientManager.CurrentTransientManager;
      IntegerCollection ic = new IntegerCollection();
      int vpn = System.Convert.ToInt32(AcAp.GetSystemVariable("CVPORT"));
      ic.Add(vpn);
      AcDb.Line ln;
      using (Transaction tr = db.TransactionManager.StartTransaction()) {
        try {
          lstDraws = new List<Drawable>();
          for (int i = 0; i < pts.Count - 1; i++) {
            ln = new Line(new Point3d(pts[i]), new Point3d(pts[i + 1]));
            ln.ColorIndex = color;
            Drawable d = (Drawable)ln;
            if (highlight)
              tm.AddTransient(d, TransientDrawingMode.Highlight, 0, ic);
            else
              tm.AddTransient(d, TransientDrawingMode.DirectShortTerm, 0, ic);
            lstDraws.Add(d);
          }
          tr.Commit();
          return true;
        }
        catch { return false; }
        finally {
          ln = new Line(); //critical, do not delete this
          ln.Dispose();
        }
      }
    }
James Maeding

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8795
  • AKA Daniel
Re: drawing temp graphics
« Reply #12 on: November 03, 2009, 08:48:18 PM »
This part does not make sense to me

Code: [Select]
finally {
          ln = new Line(); //critical, do not delete this
          ln.Dispose();
        }
« Last Edit: November 03, 2009, 08:51:21 PM by Daniel »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: drawing temp graphics
« Reply #13 on: November 03, 2009, 09:27:56 PM »
Nor do I Dan/James.

added:
in fact, when is the finally branch actually accessed. ?  (trick question perhaps )


don't have time to play, but ..

Why are you passing in a List<double[]>  and not List<Point3d[]>  ??

For consistancy, if you are going to prefix the Line Class with an Aliased Namespace
ie AcDb.Line ln;
then do it everywhere it occurs ... better for the sanity of the reader. :)

regards
Kerry
« Last Edit: November 03, 2009, 09:34:58 PM by Kerry Brown »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8795
  • AKA Daniel
Re: drawing temp graphics
« Reply #14 on: November 04, 2009, 02:16:25 AM »
Also you don't need a transaction, See if this code gives you any ideas

TransientEntity.cs
Code: [Select]
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Geometry;

namespace ExecMethod
{
 public class TransientEntityCollection : List<TransientEntity>
 {
  public void Clean(TransientManager manager)
  {
   this.ForEach(Item => Item.Clean(manager));
  }
 }

 public class TransientEntity
 {
  protected IntegerCollection m_viewportNumbers;
  protected Entity m_entity;
  protected bool m_isCleaned;

  private TransientEntity(){}

  public TransientEntity(Entity entity)
  {
   m_viewportNumbers = new IntegerCollection();
   m_entity = entity;
   m_isCleaned = false;
  }

  public TransientEntity(Entity entity, IntegerCollection viewportNumbers)
  {
   m_viewportNumbers = viewportNumbers;
   m_entity = entity;
   m_isCleaned = false;
  }

  public virtual void Clean(TransientManager manager)
  {
   manager.EraseTransient(m_entity, m_viewportNumbers);
   m_entity.Dispose();
   m_isCleaned = true;
  }

  public IntegerCollection ViewportNumbers
  {
   get { return m_viewportNumbers; }
   set { m_viewportNumbers = value; }
  }

  public bool IsCleaned
  {
   get { return m_isCleaned; }
  }

  public Entity Entity
  {
   get { return m_entity; }
  }
 }

 public class TransientLine : TransientEntity
 {
  public TransientLine(Point3d point1, Point3d point2): base(null)
  {
   base.m_entity = new Line(point1, point2);
  }
  public TransientLine(Point3d point1, Point3d point2,
   IntegerCollection viewportNumbers) : base(null, viewportNumbers)
  {
   base.m_entity = new Line(point1, point2);
  }
 }
}

command.cs
Code: [Select]
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.LayerManager;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Colors;

using AcAp = Autodesk.AutoCAD.ApplicationServices;
using AcEd = Autodesk.AutoCAD.EditorInput;
using AcGe = Autodesk.AutoCAD.Geometry;
using AcRx = Autodesk.AutoCAD.Runtime;
using AcDb = Autodesk.AutoCAD.DatabaseServices;
using AcWd = Autodesk.AutoCAD.Windows;

[assembly: CommandClass(typeof(ExecMethod.Commands))]
namespace ExecMethod
{

 public static class Commands
 {

  static TransientEntityCollection _drawn = new TransientEntityCollection();

  [CommandMethod("doit")]
  static public void doit()
  {
   TransientManager tm = TransientManager.CurrentTransientManager;

   for (int i = 0; i < 1000; i++)
   {
    TransientEntity tEnt =
      new TransientLine(
         new Point3d(0.0, 0.0, 0.0),
           new Point3d(10.0, 10.0 + (double)i, 0.0)) as TransientEntity;


    tm.AddTransient(
      tEnt.Entity,
       TransientDrawingMode.DirectTopmost, 0,
        tEnt.ViewportNumbers);

    _drawn.Add(tEnt);
   }
  }

  [CommandMethod("undoit")]
  static public void undoit()
  {
   _drawn.Clean(TransientManager.CurrentTransientManager);
  }
 }
}
« Last Edit: November 04, 2009, 03:32:44 AM by Daniel »