Points along a curve.

Points along a curve.

Ryan
Enthusiast Enthusiast
7,264 Views
11 Replies
Message 1 of 12

Points along a curve.

Ryan
Enthusiast
Enthusiast

Hi all,

 

I would like to create several XYZ points (amount defined by user spacing double) along a bound curve, which i retrived from an element.

The points would then be add to an List<XYZ>();

 

The problem is the curves run on a angle to revit's  X, Y. So im not sure where to start , otherwise i would have some code to post.

 

 

Thanks in Advance.

 

 

0 Likes
Accepted solutions (2)
7,265 Views
11 Replies
Replies (11)
Message 2 of 12

Anonymous
Not applicable

I might be able to aim you down a path. I don't 100% remember how this code works, but a few years back I wrote an add-on that had to trace walls with detail lines for fire rating.

 

On the curved walls, I grabbed the curve and used the Tessellate method on it, which got a collection of points. I would then make the first point "startPoint". Then I iterated through the points and measured the distance. If the distance was 30", I drew a line between the points and that last poitn became the new "startPoint"... lather, rinse, repeat, until I ran out of points. Seems like if you changed the distance (it's "segmentLength" in my code) to your user input, you could get what you need and collect the points instead of drawing a line. There is some stuff in there about setting Z plane for draing the line, but you can skip or ignore and use the real one if that's what you want.

 

Below is the code with some markups. Hope it helps. Apologies for any glaring formatting problems.

 

 

            Curve wallArc = (pickedWall.Location as LocationCurve).Curve;
            
IList<XYZ> wallPoints = wallArc.Tessellate(); XYZ startPoint = wallPoints.First<XYZ>(); foreach (XYZ point in wallPoints) { if (point == startPoint) { //same point - do nothing } else {
XYZ startPointZ = new XYZ(startPoint.X, startPoint.Y, curView.SketchPlane.Plane.Origin.Z); XYZ pointZ = new XYZ(point.X, point.Y, curView.SketchPlane.Plane.Origin.Z); Line curveSegment = uiApp.Application.Create.NewLineBound(startPointZ, pointZ); Double segmentLength = curveSegment.Length; //this is segmentLength that sees how far one point is from another if (segmentLength > 2.5) { // the line is long enough so draw it and start over //draw the fire line drawFireLine(doc, wallRating(pickedWall), curveSegment, whichOne); startPoint = point; } } }

 

0 Likes
Message 3 of 12

Ryan
Enthusiast
Enthusiast

Thanks jk,

 

I was trying to adapted something similar from code i got from one of Jeremy Tammik blogs.

http://thebuildingcoder.typepad.com/blog/2013/11/placing-equidistant-points-along-a-curve.html

 

But, when i run .tessellate() i only get 2 points.. A starting point and a point part part way along the line. Should i be getting more? Im still unsure of what Tessellate does...

0 Likes
Message 4 of 12

arnostlobel
Alumni
Alumni

Oops, I marked this recent post as a solution by mistake. (I clicked on a wrong link in the email). I do not know how to undo it - my apologies.

Arnošt Löbel
0 Likes
Message 5 of 12

Anonymous
Not applicable

I don't have a good answer for you on the two points issue. All I can tell you is I stripped down my program and made it to count the number of tessellated (sp?) points it found. It was more than two, but it does vary depending on how long the curve is and how "complete" a circle it is. For example, a wall that is almost a complete 360 degrees and is about 30' long gives me 66 points. The same "arc" but 250' long gives me 190 points.

 

Maybe post part of your code? I can't promise anything, but I could take a look.

0 Likes
Message 6 of 12

Ryan
Enthusiast
Enthusiast

Sorry, My bad.

 

I should have been more specific. When I was talking curve, I meant the Revit API Class Autodesk.Revit.DB.Curve, and not a circle or arc. My apologies again.

 

The Bound Line I’m trying to project these points on, is straight. But, it runs on an angle to X and Y. So, I can’t simply just subtract/add my spacing variable from/to X or Y .

 

It’s looking like there is a math equation that I am missing, or forgotten about. Perhaps I should of paid more attention in math class, haha.

0 Likes
Message 7 of 12

Anonymous
Not applicable
Accepted solution

Ah, gotcha. Yeah, junior high geometry that I forgot rears its ugly head again.

 

Maybe this is more what you need?

 

http://math.stackexchange.com/questions/175896/finding-a-point-along-a-line-a-certain-distance-away-...

Message 8 of 12

Ryan
Enthusiast
Enthusiast
Accepted solution

Yeah, its  looking like it.... Sigh. lol

 

Thanks for the help!

 

With a little more searching this moring i found some C# code that does what i need. Created a while loop for with the point.DistanceTo() method and ran the Point Calculation code in a private method.

 

  List<XYZ> pts = new List<XYZ>();

  double dist = 1;
  double length = c.Length;
 
  XYZ start = curve.GetEndPoint( 0 );
  XYZ end = curve.GetEndPoint(1);


pts.Add(start);

	XYZ point = start;
	while (start.DistanceTo(point) <= length)
		{
			point = PointCalc(point, end, dist);
			pts.Add(point);
		}
  

// Helper Method:

	        private XYZ PointCalc(XYZ start, XYZ end, double distance)
	        {
	        	
	        	
   // Origin point 
  Double origin_x = start.X;
  Double origin_y = start.Y;  

  // Point you are moving toward
  Double to_x = end.X;
  Double to_y = end.Y;


   distance = 1;

  Double fi = Math.Atan2(to_y - origin_y, to_x - origin_x);

  // Your final point
  Double final_x = origin_x + distance * Math.Cos(fi);
  Double final_y = origin_y + distance * Math.Sin(fi);
  
  XYZ xyz = new XYZ(final_x, final_y, end.Z);
  
  return xyz;
  
	        }

Thanks Again!

 

 

0 Likes
Message 9 of 12

Ryan
Enthusiast
Enthusiast

Well this is a interesting....

 

I took the previous code and applied it to what i intended. But i get a completely different result.

 

The circles in the image are generated from the same PointCalc method i mentioned above. When applied to the Structural columns, the appear offset to the wall.

 

What i dont get, is its the exact same point the circles were created on.

 

the new columns on the right should be in the same as the circles.

 

 

2015-07-15_1105_001.png

 

 

 

         	    List<XYZ> pts = StudSpaceing(1, c);
         	    
       
         
         	    
         	    using (Transaction t = new Transaction(doc,  "StudSpacingTest"))
         	    {
         	    	t.Start();
         	    	
         	    	
         	    	
         	    	foreach (XYZ p in pts)
         	    	         {
         	    		
     //Copying a stud from exsisting one, thought that was the easist way to set the same params, etc.

   	    		ElementTransformUtils.CopyElement(doc,studs.First(),p);
         	    	

	CreateCircle(doc,p,0.125);
         	    	
         	    		
         	    	         }
 				
         	    		doc.Delete(studs);
         	    
         	    		
         	    	t.Commit();
         	    }
         	       
//Helper Functions:

	        private XYZ PointCalc(XYZ start, XYZ end, double distance)
	        {
	        	
	        	
   // Origin point
  Double origin_x = start.X;
  Double origin_y = start.Y;  

  // Point you are moving toward
  Double to_x = end.X;
  Double to_y = end.Y;

  Double fi = Math.Atan2(to_y - origin_y, to_x - origin_x);

  // Your final point
  Double final_x = origin_x + distance * Math.Cos(fi);
  Double final_y = origin_y + distance * Math.Sin(fi);
  
  XYZ xyz = new XYZ(final_x, final_y, end.Z);
  
  return xyz;
  
	        }
     	    


     private List<XYZ> StudSpaceing(double dist, Curve c)
 	    {

 
 
  // Extract data from the selected curve.
 
  Curve curve = c;

  List<XYZ> pts = new List<XYZ>();

  
  double length = c.Length;
 
  XYZ start = curve.GetEndPoint( 0 );
  XYZ end = curve.GetEndPoint(1);


pts.Add(start);

	XYZ point = start;
	while (start.DistanceTo(point) < length)
		{
			point = PointCalc(point, end, dist);
			pts.Add(point);
		}
return pts;
 
  }

//Circle Creation Function:

public DetailArc CreateCircle(
    Document doc,
    XYZ location,
    double radius )
  {
    XYZ norm = XYZ.BasisZ;
 
    double startAngle = 0;
    double endAngle = 2 * Math.PI;
 
    Plane plane = new Plane( norm, location );
 
    Arc arc = Arc.Create( plane,
      radius, startAngle, endAngle );

    return doc.Create.NewDetailCurve(
      doc.ActiveView, arc ) as DetailArc;
            
     }

 

0 Likes
Message 10 of 12

Ryan
Enthusiast
Enthusiast
I realized my error,

ElementTransformUtils.CopyElement doesn't take a new XYZ but the distance the copy should travel.
0 Likes
Message 11 of 12

Anonymous
Not applicable

Why are you taking in distance to the helper method and then setting it to 1?

0 Likes
Message 12 of 12

rhanzlick
Advocate
Advocate

Not sure if you have solved this more appropriately since, but you could use the following:

 

curve.Evaluate(curve.ComputeRawParameter(input_length),false)

 

where input_length is the spacing provided by user, then use a forloop to increment input_length value.

You will just need to verify that curve.ComputeRawReferenceParameter() still lies within your curve at each iteration.

This can be done with: curve.IsInside(curve.ComputeRawParameter(input_length))

 

This process should work universally for any curve of any orientation (ie if its a circle, it will just work its way around the circle, if "straight line" will work its way down the length)