Can SketchEditScope be used to change sketch-based elements, e.g. floors?

Can SketchEditScope be used to change sketch-based elements, e.g. floors?

zhuliyi0
Enthusiast Enthusiast
2,443 Views
6 Replies
Message 1 of 7

Can SketchEditScope be used to change sketch-based elements, e.g. floors?

zhuliyi0
Enthusiast
Enthusiast

SketchEditScope is a new API feature in 2022, and I was expecting it to be able to do editing just like with the UI: enter edit mode, make change to sketch curves, then finish. However I cannot find any documentation of how to do it. I found the Sketch element retrieved by .SketchId has only read-only properties. 

 

If SketchEditScope cannot be used to freely make change, then it is not too different from the existing limited workrounds:

 

https://forums.autodesk.com/t5/revit-api-forum/editing-a-floor-profile-get-void-in-floor/m-p/7171573

 

Can anyone clarify what sketch API really can do?

0 Likes
Accepted solutions (1)
2,444 Views
6 Replies
Replies (6)
Message 2 of 7

jeremy_tammik
Alumni
Alumni

Afaict, it should do exactly what you are asking for. What's New gives a brief description:

  

https://thebuildingcoder.typepad.com/blog/2021/04/whats-new-in-the-revit-2022-api.html#4.2.1.6

   

I do not have an example at hand. I've asked the devteam for one for you.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 7

jeremy_tammik
Alumni
Alumni
Accepted solution

Here is a sample macro that was uploaded to the Revit Preview forum:

  

/*
 * Sample - Edit Floor Sketch.cs
 * Created by SharpDevelop.
 * User: t_matva
 * Date: 11/17/2020
 * Time: 11:18 AM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;
using System.Linq;
​
namespace Sample
{
    [Autodesk.Revit.Attributes.Transaction( Autodesk.Revit.Attributes.TransactionMode.Manual )]
    [Autodesk.Revit.DB.Macros.AddInId( "994A64E6-839B-4C1F-B473-1E7C614A5455" )]
    public partial class ThisDocument
    {
      private void Module_Startup( object sender, EventArgs e )
      {
      }
​
      private void Module_Shutdown( object sender, EventArgs e )
      {
      }
​
      #region Revit Macros generated code
      private void InternalStartup()
      {
        this.Startup += new System.EventHandler( Module_Startup );
        this.Shutdown += new System.EventHandler( Module_Shutdown );
      }
      #endregion
​
        public void CreateFloor()
      {
        Curve left = Line.CreateBound( new XYZ( 0, 0, 0 ), new XYZ( 0, 100, 0 ) );
        Curve upper = Line.CreateBound( new XYZ( 0, 100, 0 ), new XYZ( 100, 100, 0 ) );
        Curve right = Line.CreateBound( new XYZ( 100, 100, 0 ), new XYZ( 100, 0, 0 ) );
        Curve lower = Line.CreateBound( new XYZ( 100, 0, 0 ), new XYZ( 0, 0, 0 ) );
​
            CurveLoop floorProfile = new CurveLoop();
        floorProfile.Append( left );
        floorProfile.Append( upper );
        floorProfile.Append( right );
        floorProfile.Append( lower );
​
        ElementId levelId = Level.GetNearestLevelId( Document, 0.0 );
​
        using( Transaction transaction = new Transaction( Document ) )
        {
          transaction.Start( "Create floor" );
​
          ElementId floorTypeId = Floor.GetDefaultFloorType( Document, false );
          Floor floor = Floor.Create( Document, new List<CurveLoop>() { floorProfile }, floorTypeId, levelId );
​
          transaction.Commit();
        }
      }
​
      // Find a line in a sketch, delete it and create an arc in its place.
      public void ReplaceBoundaryLine()
      {
        FilteredElementCollector floorCollector = new FilteredElementCollector( Document )
           .WhereElementIsNotElementType()
           .OfCategory( BuiltInCategory.OST_Floors ).OfClass( typeof( Floor ) );
​
            Floor floor = floorCollector.FirstOrDefault() as Floor;
        if( floor == null )
        {
          TaskDialog.Show( "Error", "Document does not contain a floor." );
          return;
        }
​
        Sketch sketch = Document.GetElement( floor.SketchId ) as Sketch;
​
        Line line = null;
        foreach( CurveArray curveArray in sketch.Profile )
        {
          foreach( Curve curve in curveArray )
          {
            line = curve as Line;
            if( line != null )
            {
              break;
            }
          }
          if( line != null )
          {
            break;
          }
        }
​
        if( line == null )
        {
          TaskDialog.Show( "Error", "Sketch does not contain a straight line." );
          return;
        }
​
        // Start a sketch edit scope
        SketchEditScope sketchEditScope = new SketchEditScope( Document, "Replace line with an arc" );
        sketchEditScope.Start( sketch.Id );
​
        using( Transaction transaction = new Transaction( Document, "Modify sketch" ) )
        {
          transaction.Start();
​
          // Create arc
          XYZ normal = line.Direction.CrossProduct( XYZ.BasisZ ).Normalize().Negate();
          XYZ middle = line.GetEndPoint( 0 ).Add( line.Direction.Multiply( line.Length / 2 ) );
          Curve arc = Arc.Create( line.GetEndPoint( 0 ), line.GetEndPoint( 1 ), middle.Add( normal.Multiply( 20 ) ) );
​
          // Remove element referenced by the found line. 
          Document.Delete( line.Reference.ElementId );
​
          // Model curve creation automatically puts the curve into the sketch, if sketch edit scope is running.
          Document.Create.NewModelCurve( arc, sketch.SketchPlane );
​
          transaction.Commit();
        }​
        sketchEditScope.Commit( new FailuresPreprocessor() );
      }
​
      /// <summary>
      /// Add new profile to the sketch.
      /// </summary>
      public void MakeHole()
      {
        FilteredElementCollector floorCollector = new FilteredElementCollector( Document )
          .WhereElementIsNotElementType()
          .OfCategory( BuiltInCategory.OST_Floors ).OfClass( typeof( Floor ) );
​
          Floor floor = floorCollector.FirstOrDefault() as Floor;
        if( floor == null )
        {
          TaskDialog.Show( "Error", "Document does not contain a floor." );
          return;
        }
​
        Sketch sketch = Document.GetElement( floor.SketchId ) as Sketch;
​
        // Create a circle inside the floor
        // Start a sketch edit scope
        SketchEditScope sketchEditScope = new SketchEditScope( Document, "Add profile to the sketch" );
        sketchEditScope.Start( sketch.Id );
​
        using( Transaction transaction = new Transaction( Document, "Make a hole" ) )
        {
          transaction.Start();
​
          // Create and add an ellipse
          Curve circle = Ellipse.CreateCurve( new XYZ( 50, 50, 0 ), 10, 10, XYZ.BasisX, XYZ.BasisY, 0, 2 * Math.PI );
​
          // Model curve creation automatically puts the curve into the sketch, if sketch edit scope is running.
          Document.Create.NewModelCurve( circle, sketch.SketchPlane );
​
          transaction.Commit();
        }
        sketchEditScope.Commit( new FailuresPreprocessor() );
      }
    }
​
    public class FailuresPreprocessor : IFailuresPreprocessor
    {
      public FailureProcessingResult PreprocessFailures(
        FailuresAccessor failuresAccessor )
      {
        return FailureProcessingResult.Continue;
      }
    }

 

I hope this helps.

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 4 of 7

jeremy_tammik
Alumni
Alumni

Added the raw sample code to The Building Coder samples:

 

https://github.com/jeremytammik/the_building_coder_samples/compare/2022.0.150.4...2022.0.150.5

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 5 of 7

zhuliyi0
Enthusiast
Enthusiast

Thanks Jeremy, this solves my problem. I need to use Preview Forum more : )

Message 6 of 7

n_mulconray
Advocate
Advocate

I have just tried to get this great addition to the revit api to do the simple task of replacing one line with a line that is not off axis.

I am the start stage where I have tried to run the module posted by Jeremmy, thanx btw.

I am getting as far as deletion and then the exceptions might be swallowed by the failures preprocessor, however i am not seeing the line update, i am using metric revit and calling in a modeless dialog context from an external command. I noticed the arc is nearly twice the line segment length and so the line and arc are generated successfully, not sure why the delete command? might be stalling.

 

using (Transaction t = new Transaction(doc, "Modify Sketch"))
{
   t.Start();
    XYZ normal = line.Direction.CrossProduct(XYZ.BasisZ).Normalize().Negate();
    XYZ middle = line.GetEndPoint(0).Add(line.Direction.Multiply(line.Length / 2));
    Curve arc = Arc.Create(line.GetEndPoint(0), line.GetEndPoint(1), middle.Add(normal.Multiply(20)));

//can get line and arc length
    doc.Delete(line.Reference.ElementId);
//nothing returned here as task dialog nor error...
    TaskDialog.Show("del", "delete");

    ModelCurve mc = doc.Create.NewModelCurve(arc, sketch.SketchPlane);
t.Commit();
}

 

 

 

public class FailuresPreprocessor : IFailuresPreprocessor
{
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
{
return FailureProcessingResult.Continue;
}
}

0 Likes
Message 7 of 7

n_mulconray
Advocate
Advocate

No worries this is solved by copy pasting from the github instead of the forum the sketch edit group trtansaction section of the code. I noted comma errors in VS and this might be the reason or maybe I made some error.

 

0 Likes