Esses dias comecei a trabalhar em um projeto novo que envolve a inserção de setas com informações no desenho. Buscando um pouco me deparei com esse artigo do Kean Walmsley de como posicionar uma seta com o texto pré-inserido.
Isso realmente é um problema, quem usa essa ferramenta de seta (que no meu trabalho é uma raridade, setas são feitas para serem explodidas!) sabe que é dramático você escolhe uma posição para a seta e o ponto de inflexão depois escreve o texto, finalmente você nota que ficou ruim e é obrigado a editar a posição.
O truque é usar o MLeader a partir de um EntityJig. Primeiro passo usado pelo Kean foi tornar o MLeader seja database-resident para ser acionado - uma técnica que é bastante comum ao movimentar sólidos ou blocos com atributos (sem perder as informações contidas nele). O MText aparece no início do líder e, em seguida, o líder é exibido da origem até movermos o mouse para iniciar o ciclo Sampler/Update no jig.
Segue o código em C#:
using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; namespace AtuoCADNetBlog_Ex240420 { public class myLeader { class DirectionalLeaderJig : EntityJig { private Point3d _start, _end; private string _contents; private int _index; private int _lineIndex; private bool _started; public DirectionalLeaderJig(string txt, Point3d start, MLeader ld) : base(ld) { // Store info that's passed in, but don't init the MLeader _contents = txt; _start = start; _end = start; _started = false; } // A fairly standard Sampler function protected override SamplerStatus Sampler(JigPrompts prompts) { var po = new JigPromptPointOptions(); po.UserInputControls = (UserInputControls.Accept3dCoordinates | UserInputControls.NoNegativeResponseAccepted); po.Message = "\nEnd point"; var res = prompts.AcquirePoint(po); if (_end == res.Value) { return SamplerStatus.NoChange; } else if (res.Status == PromptStatus.OK) { _end = res.Value; return SamplerStatus.OK; } return SamplerStatus.Cancel; } protected override bool Update() { var ml = (MLeader)Entity; if (!_started) { if (_start.DistanceTo(_end) > Tolerance.Global.EqualPoint) { // When the jig actually starts - and we have mouse movement - // we create the MText and init the MLeader ml.ContentType = ContentType.MTextContent; var mt = new MText(); mt.Contents = _contents; ml.MText = mt; // Create the MLeader cluster and add a line to it _index = ml.AddLeader(); _lineIndex = ml.AddLeaderLine(_index); // Set the vertices on the line ml.AddFirstVertex(_lineIndex, _start); ml.AddLastVertex(_lineIndex, _end); // Make sure we don't do this again _started = true; } } else { // We only make the MLeader visible on the second time through // (this also helps avoid some strange geometry flicker) ml.Visible = true; // We already have a line, so just set its last vertex ml.SetLastVertex(_lineIndex, _end); } if (_started) { // Set the direction of the text to depend on the X of the end-point // (i.e. is if to the left or right of the start-point?) var dl = new Vector3d((_end.X >= _start.X ? 1 : -1), 0, 0); ml.SetDogleg(_index, dl); } return true; } } [CommandMethod("LEADER2")] public void myleadercommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; Database db = doc.Database; // Pede ao usuário para inserir o texto PromptStringOptions promptso = new PromptStringOptions("\nEntre com o Texto:"); promptso.AllowSpaces = true; //Caso queira manter um texto vazio pára isnerir e pré-visualizar promptso.DefaultValue = "TEXTO"; PromptResult pResult = ed.GetString(promptso); //Trata o caso que o usuário não entrou com valor ou entrou com um valor inválido if (pResult.Status != PromptStatus.OK) return; //Pede para o usuário entrar com o ponto da seta. PromptPointResult ppResult = ed.GetPoint("\nSelecione o ponto inicial da seta"); //Trata o erro de seleção do ponto if (ppResult.Status != PromptStatus.OK) return; // Para manipular os objetos tipo db-resident é necessário usar a transaction using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead, false); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite, false); // Criando e passando as informações através de um objeto MLEADER //existe outras formas de fazer mas desse jeito a seta nao fica com a tela psicando e não tem risco do usuário //acabar clicando em algum lugar e dando um fatality no AutoCAD. MLeader mymleader = new MLeader(); //deixa invesivel mymleader.Visible = false; // Criando o jig var jig = new DirectionalLeaderJig(pResult.StringResult, ppResult.Value, mymleader); // Inclui o objeto já com a posição definida no desenho btr.AppendEntity(mymleader); tr.AddNewlyCreatedDBObject(mymleader, true); // Insere o objeto na tela. PromptResult pJigResult = ed.Drag(jig); // If all is well, commit if (pJigResult.Status == PromptStatus.OK) { tr.Commit(); } else { ed.WriteMessage("Ocorreu um erro na criação da seta, tente novamente."); } } } } }
Esse código tem muita aplicação, quem quiser só utilizar já está até compilado, abaixo está a solução do projeto para quem quiser compilar também
Download
Espero ter ajudado mais alguém, até o próximo!
Comentários
Postar um comentário