SimA Posted April 29 Share Posted April 29 Hello everyone I'm looking for a way or node like "point on poly". However, the point on the polyline should be defined by the chord and not the distance along the guideline. Thanks for your help. Quote Link to comment
Pat Stanford Posted April 29 Share Posted April 29 I know there is not a simple built in way to do this. But I am not certain how I would approach this if it was my problem. It is simple to get a visual representation of the intersection by drawing a circle from the first point with a radius equal to the chord length you want. The hard part is actually getting the intersection as none of the intersect routines in the Graphical Calculation section of the VS Function Reference appear to work with Polylines. Maybe convert a copy of the polyline to Lines, which should give you a group of lines. Then check each line for intersection with the circle? @Sam Jones We had a conversation 20 years ago about Chords. Any help here? And a call to the regular VS warriors @MullinRJ @JBenghiat @michaelk @Jesse Cogswell Quote Link to comment
Sam Jones Posted April 29 Share Posted April 29 No help here. I haven't a clue. I'll go out on a limb and say VS is not up to it, but would be delighted to be shown I was wrong. I started listing a bunch of issues here, but it got crazy. Why do you want to have this functionality? How would you like to use it? @MullinRJ have you got a magic vector math solution? Quote Link to comment
MullinRJ Posted April 30 Share Posted April 30 @Pat Stanford, @Sam Jones, Without a built-in function, this is a very complicated problem. Polylines can be drawn many different ways, with a mixture of control point types. Calculating Line intersections with straight and arc segments is relatively straight forward, but intersections with bezier and cubic sections are much more complicated and require iterative solutions. At one time I started trying to solve this problem but only got so far and could not model every combination of control points that can make up a poly line. In that effort there were several hundred lines of code – and I never finished. Without a firm understanding of Cubic Spline algebra and the ways VW implements a subset of it, I would not suggest one stroll too far down this path. If you do, bring plenty of bread crumbs. You may need them to find your way home. If approximate results are good enough, perhaps Pat's suggestion of converting the Polyline to Lines, or a Polygon, first, might be the way to go. Beware, I converted a 9 point Polyline to a Polygon and got 68 vertices on a 2D Conversion Resolution of Low, and 1804 vertices with a 2D Conversion Resolution of Very High. The Polyline conversion at Low Resolution may have a manageable number of segments, but the accuracy may not be acceptable. Whereas the higher resolutions may provide the accuracy, but the vertex count will be in the hundreds, if not thousands, and computation time will be noticeably slow. Remember you not only have to find the intersection of two lines, one pair at a time, but you also have to determine of the intersection point is on the line segment. Sorry I couldn't be of greater assistance. ******** STOP THE PRESS! ******** All of that said — take a look at the IntersectSurface() function. This is not one I've played with before, but on a whim I just tried the menu command and it could be quite useful, if you can devise a meaningful way to harvest your results. In Vectorscript the command is: H := IntersectSurface(LineHand, PolyHand); You will get multiple line segments as the Polyline will dice the line into pieces. There are scenarios where all endpoints of the resultant lines land on the poly (even number of intersections), and some where the last point does not touch the poly, but it is needed to preserve the last line segment (odd number of intersections). This command is not the total answer and will require some extra code to be useful. I'll leave that to others. It's past my bed time, so I'm going to call it quits here. Good luck, Raymond Quote Link to comment
Pat Stanford Posted April 30 Share Posted April 30 My reading of the question is that @SimA wants to define the chord length and then calculate where that chord length next contacts the polyline. So drawing the circle at the first point is relatively easy. And comparing even a few thousand lines to intersect the circle should not be too bad as it can be solved in linear time not exponential time since you don't need to compare every line to each other. And maybe add the bounding box check we discussed in the other thread so you don't have to actually test objects that dont' have any chance of being the chord. But a better description of what is actually being done and why might let us generate better options. 1 Quote Link to comment
MullinRJ Posted April 30 Share Posted April 30 Good morning, @Pat Stanford. If the path object is a Polygon, I think I've solved that before. Let me look and I'll get back... Raymond 1 Quote Link to comment
MullinRJ Posted April 30 Share Posted April 30 ... The problem I solved was similar, but not the same. My solution assumed the chord length was less than the line/poly segments, where this solution must assume the chord length can be longer or shorter than the line/poly segments. Other questions need to be answered. Since this is supposed to be a Marionette node, what constraints exist for the inputs, and what format is the output? Whatever the answers, this is not going to be an easy solution. Raymond Quote Link to comment
SimA Posted May 1 Author Share Posted May 1 Hello everyone I plan and project kitchens, shop fittings, bakeries, counters and much more. Until recently, these were mostly cubic and angular. Organic forms are now often required. The furniture usually has fixed axis lengths or standard widths. "Point on Poly" works more or less well because the chord is too short because the length is calculated along the polyline. Now when it comes to execution, I have to determine the intersection points with circles. This procedure takes a lot of time because several drawings often have to be made. I have attached my file with the current marionette. This certainly explains it better than my Google translated one. Another thought: a curved line is always longer than a direct straight line connecting two points. I tried using a loop in the code to move the point on the line until it was at the intersection of the chord. The shifting was done, for example, in tenths of the difference between chord and nDist up to an accuracy of 0.000000x. The problem was that the point was calculated from the polyline starting point. However, I would need a continuous calculation from point A to B to C etc. Unfortunately, I failed because of my ignorance and GPT. Thank you for all your ideas! Kontur Aufteilung.vwx Quote Link to comment
MullinRJ Posted May 1 Share Posted May 1 Hello @SimA, Are all of your chords the same length or will they differ as you go down the line (um, curve?) Raymond Quote Link to comment
SimA Posted May 1 Author Share Posted May 1 Hallo @MullinRJ Most are different. Quote Link to comment
JBenghiat Posted May 2 Share Posted May 2 Vectorworks doesn’t have this intersection function in its API. To truly solve this mathematically, you would need to use the control points and arc types of each polyline segment, then intersect with a circle, but that is probably overkill. I can think of two solutions: Use PointAlongPoly(). The length will be >= your chord length, so start with that as an initial value, and increase your length by 1mm until the distance from the start point to the end point >= your chord length. For subsequent points, set your start point to the found point, and the start length to the found length + chord length. Call Polygonize() on the original polyline with a segment length of 1mm, then iterate over the new polygon’s points, developing a list of start and and points whose distance equals your chord length. I believe this is essentially what pointalongpoly is doing under the hood. Obviously, you can change 1mm to wherever your tolerance is. 1 Quote Link to comment
JBenghiat Posted May 2 Share Posted May 2 And if you really wanted to automate things, you would have a list of stock sizes and a constant representing the maximum angle between segments. You would try successively smaller chord lengths from your list until you either were under your angle tolerance or reached the end of the list. Quote Link to comment
SimA Posted May 5 Author Share Posted May 5 The chord is now calculated from p1. However, processing the list would also have to use a sequence of consecutive points. How do I have to incorporate this into the code? import vs import math import Marionette @Marionette.NodeDefinition class Params(metaclass=Marionette.OrderedClass): # APPEARANCE # Name this = Marionette.Node("Get Point on Poly and Distance") this.SetDescription('Returns a point at the specified distance along the poly starting from the first vertex of the poly, and calculates the distance between two points') # Input Ports poly = Marionette.PortIn(vs.Handle(0), 'hPoly') poly.SetDescription("The input poly") nDist = Marionette.PortIn(0, 'nDist') nDist.SetDescription("The specified distance") p1 = Marionette.PortIn((0, 0), 'p1') p1.SetDescription("A 2D point representing the start point") nSehne = Marionette.PortIn(0, 'nSehne') nSehne.SetDescription("A specified length representing the radius of a circle") # OIP Controls tolerance = Marionette.OIPControl('Tolerance', Marionette.WidgetType.Text, '0.0000001') tolerance.SetDescription("An acceptable difference between the calculated and approximate values") # Output Ports p2 = Marionette.PortOut('p2') p2.SetDescription("The result point") vTan = Marionette.PortOut('vTan') vTan.SetDescription("The vector tangent to the poly at the result point") b = Marionette.PortOut('b') b.SetDescription("True if the node completes its job successfully, false otherwise") # BEHAVIOR def RunNode(self): # inputs poly = self.Params.poly.value dist = self.Params.nDist.value tolerance = self.Params.tolerance.value p1 = self.Params.p1.value nSehne = self.Params.nSehne.value # script result = vs.PointAlongPolyN(poly, dist, tolerance) p2 = result[1] vTan = result[2] # Calculate distance between p1 and p2 c = Marionette.TupleMap(lambda x, y: (y - x) ** 2, p1, p2) l = math.sqrt(sum(c)) # If the distance between p1 and p2 is greater than or equal to nSehne, extend the distance until it reaches nSehne while l < nSehne: dist += 1 # Increase dist by 1 unit result = vs.PointAlongPolyN(poly, dist, tolerance) p2 = result[1] vTan = result[2] c = Marionette.TupleMap(lambda x, y: (y - x) ** 2, p1, p2) l = math.sqrt(sum(c)) # outputs self.Params.b.value = result[0] self.Params.p2.value = result[1] self.Params.vTan.value = result[2] Quote Link to comment
SimA Posted May 5 Author Share Posted May 5 import vs import math import Marionette @Marionette.NodeDefinition class Params(metaclass=Marionette.OrderedClass): # Erscheinungsbild # Name this = Marionette.Node("Get Point on Poly and Distance") this.SetDescription('Gibt einen Punkt an der angegebenen Entfernung entlang des Polygons zurück, beginnend vom ersten Eckpunkt des Polygons, und berechnet die Entfernung zwischen zwei Punkten') # Eingabeanschlüsse poly = Marionette.PortIn(vs.Handle(0), 'hPoly') poly.SetDescription("Das Eingabepolygon") nDist = Marionette.PortIn(0, 'nDist') nDist.SetDescription("Die angegebene Entfernung") p1 = Marionette.PortIn((0, 0), 'p1') p1.SetDescription("Ein 2D-Punkt, der den Startpunkt repräsentiert") nSehne = Marionette.PortIn(0, 'nSehne') nSehne.SetDescription("Eine angegebene Länge, die den Radius eines Kreises repräsentiert") # OIP-Steuerungen tolerance = Marionette.OIPControl('Toleranz', Marionette.WidgetType.Text, '0.0000000000001') tolerance.SetDescription("Ein akzeptabler Unterschied zwischen den berechneten und approximierten Werten") # Ausgabeanschlüsse p2 = Marionette.PortOut('p2') p2.SetDescription("Der Ergebnispunkt") vTan = Marionette.PortOut('vTan') vTan.SetDescription("Der Vektor tangential zum Polygon am Ergebnispunkt") b = Marionette.PortOut('b') b.SetDescription("True, wenn der Knoten seine Aufgabe erfolgreich abschließt, sonst False") # VERHALTEN def RunNode(self): # Eingaben poly = self.Params.poly.value dist = self.Params.nDist.value tolerance = self.Params.tolerance.value p1 = self.Params.p1.value nSehne = self.Params.nSehne.value # Skript result = vs.PointAlongPolyN(poly, dist, tolerance) p2 = result[1] vTan = result[2] # Berechnen der Entfernung zwischen p1 und p2 c = Marionette.TupleMap(lambda x, y: (y - x) ** 2, p1, p2) l = math.sqrt(sum(c)) # Annäherung in noch kleineren Schritten und Präzisierung in noch kleineren Schritten while l < nSehne: new_dist = dist + 0.000001 # Annäherung in noch kleineren Schritten if new_dist >= nSehne: # Überprüfe, ob die neue Entfernung nSehne überschreiten würde break else: # Präzisierung in noch kleineren Schritten step = 0.00000001 while dist < new_dist: dist += step result = vs.PointAlongPolyN(poly, dist, tolerance) p2 = result[1] vTan = result[2] c = Marionette.TupleMap(lambda x, y: (y - x) ** 2, p1, p2) l = math.sqrt(sum(c)) # Ausgaben self.Params.b.value = result[0] # Koordinaten mit höherer Genauigkeit erfassen self.Params.p2.value = (round(result[1][0], 15), round(result[1][1], 15)) self.Params.vTan.value = result[2] Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.