1

I have been trying to create a tool that creates a line using points. The idea in my mind is to get the points from a onmousedown Event and putting them in generic list and draw the line geometries using those points onmousemove exactly like placing a transmedia from a Model Pallate in ArcMap.

I am able to place points on map. But I am unable to create lines on move. I was thinking if I would get the point on onmousemove but was clueless how to do that. Even how to stop the onmousemove. I do not try to use the line feedback or any handler for creating this. I was thinking to create the tool from scratch not taking help from any other tool.

  • Did you try a NewLineFeedback, as shown in this sample? – Kirk Kuykendall Aug 16 '18 at 16:46
  • Hello Kirk, sorry for the late response, actually I wanted myself to create a geometry (point and line) and using the tool framework. I know there is linefeedback but I did not want to use any other handler for this. I wished Geometry, Display and the Basetool is enough to draw it on map. But I am stuck. – royan Aug 20 '18 at 10:19
  • In that case, I would recommend implementing IDisplayFeedback2 – Kirk Kuykendall Aug 20 '18 at 14:57
0

Here's a bit of old code that might help, not so much with the generating of your geometries as this tool tracks multiple lines to the current mouse location, but the method of generating a geometry in your OnMouseMove then drawing it in a different event.

protected override void OnMouseMove(MouseEventArgs arg)
{
    int X = arg.X; // screen coordinates, in pixels from upper left
    int Y = arg.Y;

    gMidPoint = gDispTran.ToMapPoint(X, Y); // get the screen point as a map point

    // update the refesh envelope with how far the mouse has travelled - this object was created elsewhere on mouse down
    if (gMidPoint.X < gRefreshEnvelope.XMin) gRefreshEnvelope.XMin = gMidPoint.X;
    if (gMidPoint.X > gRefreshEnvelope.XMax) gRefreshEnvelope.XMax = gMidPoint.X;
    if (gMidPoint.Y < gRefreshEnvelope.YMin) gRefreshEnvelope.YMin = gMidPoint.Y;
    if (gMidPoint.Y > gRefreshEnvelope.YMax) gRefreshEnvelope.YMax = gMidPoint.Y;

    IPointCollection pDrawPC;
    IGeometryCollection pDrawGC = new PolylineClass();

    // create a part for each tracked line
    foreach (IPointCollection pThisPC in gLinePolyDrawList)
    {
        pDrawPC = new PathClass();
        // add the first point and then the mouse location (snapped if applicable)
        pDrawPC.AddPoint(pThisPC.get_Point(0), ref gMissing, ref gMissing);
        pDrawPC.AddPoint(gMidPoint, ref gMissing, ref gMissing);

        // if there's a second point (i.e. not an end) then add that
        if (pThisPC.PointCount > 1) pDrawPC.AddPoint(pThisPC.get_Point(1), ref gMissing, ref gMissing);

        // add the path to the polyline
        pDrawGC.AddGeometry((IGeometry)pDrawPC, ref gMissing, ref gMissing);
    }

    // make it into a geometry and set the spatial reference... only
    // lines with a spatial reference can be drawn.
    gDrawGeometry = (IGeometry)pDrawGC;
    gDrawGeometry.SpatialReference = gMap.SpatialReference;

    // extend the envelope to include all of the tracked paths
    gRefreshEnvelope.Union(gDrawGeometry.Envelope);

    // do a partial refresh of just the area that has been (possibly) modified
    gDoc.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, gRefreshEnvelope);
    Application.DoEvents();
}

void AfterDraw(IDisplay Display, esriViewDrawPhase phase)
{
    // draws the lines that are created during the OnMouseMove
    if (phase == esriViewDrawPhase.esriViewGeography)
    {
        if (!gSelectionStarted) return; // a boolean switch to say that there is a geometry
        gScreenDis = gDoc.ActiveView.ScreenDisplay;
        gScreenDis.SetSymbol(gSym);
        gScreenDis.DrawPolyline(gDrawGeometry);
    }
}

In the OnMouseMove event a geometry is created and then the envelope of the affected area is updated with partial refresh (quicker than refresh) which fires the event AfterDraw (wired on startup with ((IActiveViewEvents_Event)gDoc.FocusMap).AfterDraw += new IActiveViewEvents_AfterDrawEventHandler(AfterDraw);.. you can only draw to the screen between the phases of IDisplay.StartDrawing and FinishDrawing except when the view is already being refreshed. gSym is a line symbol; note you can only set one each of line, point and polygon symbols as current draw symbols, using SetSymbol again with an ISymbol of a previously set type will overwrite the existing setting.

  • Hello Michael, Thanks for putting you valuable comment and your code for achieving the one. By this time I have come up another way (Not sure right or wrong). I just want to share this. Below in the section of giving answers I am putting whatever I tried and I got in these days. – royan Aug 31 '18 at 8:10
1
public override void OnMouseDown(int Button, int Shift, int X, int Y)
        {
            // TODO:  Add tool.OnMouseDown implementation

            IPoint point = screenDisplay.DisplayTransformation.ToMapPoint(X, Y);
            CompleteGeometryAsElement(point);
            pointcollection.Add(point);
            activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
        }

        public override void OnMouseMove(int Button, int Shift, int X, int Y)
        {
            // TODO:  Add tool.OnMouseMove implementation
            if (pointcollection.Count > 0)
            {
                IPoint point = screenDisplay.DisplayTransformation.ToMapPoint(X, Y);
                CompleteGeometryAsElement(point);
                activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
            }

        }

void CompleteGeometryAsElement(IPoint point)
        {
            try
            {
                if (pointcollection.Count == 0)
                {
                    IMarkerElement markerElement = new MarkerElementClass();
                    markerElement.Symbol = simpleMarkerSymbol;
                    element = markerElement as IElement;
                    element.Geometry = point;
                    currentElement = element;
                    graphicsContainer.AddElement(currentElement, 0);
                    previousElement = currentElement;
                }
                else if (pointcollection.Count == 1)
                {
                    ILineElement lElement = new LineElementClass();
                    lElement.Symbol = lineSymbol;

                    // Border; thinkness etc to be included
                    IPolyline pl = new PolylineClass();
                    pl.FromPoint = pointcollection[0];
                    pl.ToPoint = point;
                    element = lElement as IElement;
                    element.Geometry = pl;
                    graphicsContainer.DeleteElement(previousElement);
                    currentElement = element;
                    graphicsContainer.AddElement(currentElement, 0);
                    //graphicsContainer.UpdateElement(element, 0);
                    previousElement = currentElement;
                }
                else if (pointcollection.Count > 1)
                {
                    IFillShapeElement fElement = new PolygonElementClass();
                    fElement.Symbol = simpleFillSymbol;
                    IPointCollection pColl = new PolygonClass();
                    // Border; thinkness etc to be included
                    //IPointCollection pColl = new PointArrayClass() as IPointCollection;
                    foreach (IPoint p in pointcollection)
                    {
                        pColl.AddPoint(p);
                    }
                    pColl.AddPoint(point);
                    IPolygon pgn = pColl as IPolygon;

                    element = fElement as IElement;
                    element.Geometry = pgn;
                    pgn.Close();
                    graphicsContainer.DeleteElement(previousElement);
                    currentElement = element;
                    graphicsContainer.AddElement(currentElement, 0);
                    previousElement = currentElement;
                }
            }
            catch (Exception exp)
            {

            }

        }
  • That should work too, you're adding an element - like a drawing with the draw toolbar, then calling partial refresh in your onmousemove event to limit to only the graphics draw phase. +1 for the working code. The method I use in my answer is to draw the graphic for each refresh without persisting to an element object which suited the rest of the code not shown. You might consider implementing the section about limiting the envelope of the refresh, this is particularly useful if you've got a lot of objects on that draw phase but may not speed up the refresh much otherwise. – Michael Stimson Sep 1 '18 at 11:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.