Change the size of blocks based on the Polyline

Change the size of blocks based on the Polyline

prem_kumar8SXZJ
Enthusiast Enthusiast
2,354 Views
10 Replies
Message 1 of 11

Change the size of blocks based on the Polyline

prem_kumar8SXZJ
Enthusiast
Enthusiast

Hi Everyone, I am working on a project with a polyline that is like a curve shape, and some blocks intersect that polyline. When I make changes in the curve polyline, like increasing or decreasing the curve's height, I want the blocks to also change their height based on the polyline. I have a working code that works perfectly on polylines, but I don't know how to do this for blocks. I have attached one image for the same. Thank you.

 

I appreciate any help you can provide.

0 Likes
Accepted solutions (1)
2,355 Views
10 Replies
Replies (10)
Message 2 of 11

essam-salah
Advisor
Advisor

hi @prem_kumar8SXZJ 

the problem isn't clear, have u tried obj.TransformBy() method

0 Likes
Message 3 of 11

ActivistInvestor
Mentor
Mentor

Your problem statement is not entirely clear.

 

For example, when you say 'I want the blocks to also change their height based on the polyline', do you mean the Position of the blocks or do you mean that the block's contents change in some way? Your image suggests the former, but leaves some doubt.

 

If the blocks are static blocks and only their position changes according to the polyline location, constraints could be used to move them relative to the polyline's location. at a given point along it.

 

However, a picture is not enough to answer these questions. I would suggest posting a DWG file containing an example, showing 'before' and 'after' versions of the geometry showing how objects should react to changes to other, related objects.

0 Likes
Message 4 of 11

prem_kumar8SXZJ
Enthusiast
Enthusiast

Hi @ActivistInvestor,Thank you for responding to my problem. I have attached a dwg file showing the before and after geometry. Please have a look and suggest how I can achieve the desired output. Thanks.

0 Likes
Message 5 of 11

ActivistInvestor
Mentor
Mentor

Simple question: How does the polyline change?  By direct user editing, by code, or both?

0 Likes
Message 6 of 11

prem_kumar8SXZJ
Enthusiast
Enthusiast

The polyline is changed by using code. Here it the function that changes the polyline based on the peakHeight variable.

 

private Polyline CurveFromPoly(Polyline originalPolyline)
{
    if (originalPolyline == null)
    {
        throw new ArgumentNullException(nameof(originalPolyline), "Original polyline cannot be null.");
    }

    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;

    Polyline curvePolyline = null;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

        curvePolyline = new Polyline();
        btr.AppendEntity(curvePolyline);
        tr.AddNewlyCreatedDBObject(curvePolyline, true);

        // Copy properties from original polyline
        curvePolyline.Linetype = originalPolyline.Linetype;
        curvePolyline.Color = originalPolyline.Color;
        curvePolyline.Layer = originalPolyline.Layer;
        curvePolyline.LinetypeScale = originalPolyline.LinetypeScale;

        double totalLength = originalPolyline.Length;
        double peakHeight = 25.0;

        // Define section lengths
        double startStraightLength = totalLength * 0.1;
        double startCurveLength = totalLength * 0.15;
        double middleStraightLength = totalLength * 0.5;
        double endCurveLength = startCurveLength;
        double endStraightLength = startStraightLength;

        // Step size for smooth curve
        int curvePoints = 20;

        // 1. Start straight section
        for (double i = 0; i <= startStraightLength; i += startStraightLength / 10)
        {
            Point3d pointAlongPolyline = originalPolyline.GetPointAtDist(i);
            Point2d newPoint = new Point2d(pointAlongPolyline.X, pointAlongPolyline.Y);
            curvePolyline.AddVertexAt(curvePolyline.NumberOfVertices, newPoint, 0, 0, 0);
        }

        // 2. Rising curved section with smooth transition
        for (int i = 0; i <= curvePoints; i++)
        {
            double t = i / (double)curvePoints;
            double distance = startStraightLength + t * startCurveLength;

            // Use sine function for smooth start of curve
            double heightOffset = peakHeight * Math.Sin(t * Math.PI / 2);

            Point3d pointAlongPolyline = originalPolyline.GetPointAtDist(distance);
            Point2d newPoint = new Point2d(pointAlongPolyline.X, pointAlongPolyline.Y + heightOffset);
            curvePolyline.AddVertexAt(curvePolyline.NumberOfVertices, newPoint, 0, 0, 0);
        }

        // 3. Middle straight section at peak height
        for (double i = startStraightLength + startCurveLength; i <= startStraightLength + startCurveLength + middleStraightLength; i += middleStraightLength / 10)
        {
            Point3d pointAlongPolyline = originalPolyline.GetPointAtDist(i);
            Point2d newPoint = new Point2d(pointAlongPolyline.X, pointAlongPolyline.Y + peakHeight);
            curvePolyline.AddVertexAt(curvePolyline.NumberOfVertices, newPoint, 0, 0, 0);
        }

        // 4. Declining curved section with smooth transition
        for (int i = 0; i <= curvePoints; i++)
        {
            double t = i / (double)curvePoints;
            double distance = startStraightLength + startCurveLength + middleStraightLength + t * endCurveLength;

            // Use cosine function for smooth end of curve
            double heightOffset = peakHeight * Math.Cos(t * Math.PI / 2);

            Point3d pointAlongPolyline = originalPolyline.GetPointAtDist(distance);
            Point2d newPoint = new Point2d(pointAlongPolyline.X, pointAlongPolyline.Y + heightOffset);
            curvePolyline.AddVertexAt(curvePolyline.NumberOfVertices, newPoint, 0, 0, 0);
        }

        // 5. End straight section
        for (double i = startStraightLength + startCurveLength + middleStraightLength + endCurveLength; i <= totalLength; i += endStraightLength / 10)
        {
            Point3d pointAlongPolyline = originalPolyline.GetPointAtDist(i);
            Point2d newPoint = new Point2d(pointAlongPolyline.X, pointAlongPolyline.Y);
            curvePolyline.AddVertexAt(curvePolyline.NumberOfVertices, newPoint, 0, 0, 0);
        }

        tr.Commit();
    }

    return curvePolyline;
}
0 Likes
Message 7 of 11

ActivistInvestor
Mentor
Mentor

In that case, the solution is fairly trivial. Attached is your DWG with a modified copy of the Block, that has a "Height" dynamic property that you can set to the distance from the insertion point to the polyline measured along the y-axis.

 

 

0 Likes
Message 8 of 11

prem_kumar8SXZJ
Enthusiast
Enthusiast

Yes, I already created the dynamic block and I am changing its value through code. The height is also changing. But the problem is how can I associate the height changes based on the curve polyline. So that I don't have to manually change each block's height, the height of all the blocks should change based on the curve height.

Here is the function in which I am changing the height of the block.

 

public void ModifyBlockLength()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        try
        {
            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a dynamic block: ");
            peo.SetRejectMessage("\nSelected entity is not a block.");
            peo.AddAllowedClass(typeof(BlockReference), true);

            PromptEntityResult per = ed.GetEntity(peo);

            if (per.Status != PromptStatus.OK)
            {
                return;
            }

            BlockReference blkRef = tr.GetObject(per.ObjectId, OpenMode.ForRead) as BlockReference;
            if (!blkRef.IsDynamicBlock)
            {
                ed.WriteMessage("\nSelected block is not dynamic.");
                return;
            }
            DynamicBlockReferencePropertyCollection dynProps = blkRef.DynamicBlockReferencePropertyCollection;

            foreach (DynamicBlockReferenceProperty prop in dynProps)
            {
                if (prop.PropertyName == "Height")
                {
                    blkRef.UpgradeOpen();
                    double currentValue = Convert.ToDouble(prop.Value);
                    PromptDoubleOptions pdo = new PromptDoubleOptions($"\nCurrent Length: {currentValue}\nEnter new length: ")
                    {
                        AllowNegative = false,
                        AllowZero = false
                    };

                    PromptDoubleResult pdr = ed.GetDouble(pdo);

                    if (pdr.Status == PromptStatus.OK)
                    {
                        prop.Value = pdr.Value;
                        ed.WriteMessage($"\nUpdated length to {pdr.Value}");
                    }
                    else
                    {
                        ed.WriteMessage("\nNo changes made to the block length.");
                    }

                    blkRef.DowngradeOpen();
                }
            }
            tr.Commit();
            ed.Regen();
        }
        catch (System.Exception ex)
        {
            ed.WriteMessage($"\nError: {ex.Message}");
        }
    }
}
0 Likes
Message 9 of 11

ActivistInvestor
Mentor
Mentor
Accepted solution

You have to store references to the block insertions in the polyline, using an ExtensionDictionary/XRecord with its XlateReferences property set to true. You also have to contend with copying the polyline and/or the referenced blocks, and how you'll handle that, if copying those objects is a legitimate user operation.

 

You can have a look at this thread for some help with creating the XRecord, and you can search the discussion group using terms like 'SoftPointerId', etc. for more examples.

 

Storing the Ids of the block references on the polyline will allow you to open each block reference and update its dynamic property from within the code that changes the polyline. If you're not sure how to calculate the value that you have to assign to each block, it should be the distance from the block's insertion point to the point where the polyline intersects a line passing through the insertion point along the Y-axis. 

Message 10 of 11

prem_kumar8SXZJ
Enthusiast
Enthusiast

Okay Thank you! I will try and let you know if this works.

0 Likes
Message 11 of 11

prem_kumar8SXZJ
Enthusiast
Enthusiast

Hi @ActivistInvestor, Thanks a lot for your guidance. I have written the code based on what you have suggested and it works like magic. Thanks again. Happy Coding 🙂 

0 Likes