Jump to content

MullinRJ

Member
  • Posts

    2,007
  • Joined

  • Last visited

Everything posted by MullinRJ

  1. Kevin, I was going to post here earlier today and suggest you use a two line script: DSelectAll; SelectObj ( (FSZ >= 11) & (FSZ <= 12) ); but when I tried it I realized FSZ is broken, actually it never really worked. FSZ only works with integer point sizes. So I entered a bug report and reworked an old script of mine that should work for you. Try this: PROCEDURE SelectPtSizeRange; { Select all text objects in a range of point sizes. } { 25 Nov 2003 - Raymond J Mullin } { 08 Aug 2016 - Rewrite with ForEachObject. } CONST DefaultLo = '9'; DefaultHi = '11'; VAR Lower, Upper: Real; Procedure SelectIt(H :Handle); Var PtSize :Real; Begin PtSize := GetTextSize(H, 0); if (PtSize >= Lower) & (PtSize <= Upper) then SetSelect(H); End; { SelectIt } BEGIN DSelectAll; PtDialog('Select Text Between Point Sizes: X=Lower & Y=Upper', DefaultLo, DefaultHi, Lower, Upper); if not DidCancel then ForEachObject(SelectIt, InSymbol & (T=Text)); END; { SelectPtSizeRange } Run(SelectPtSizeRange); HTH, Raymond
  2. Matt, Thanks for standing on half your ground. Raymond
  3. Matt, I like the first half of your statement, but the second half disagrees with my observations, unless my measurements and conclusions are flawed. If a set of Loci are placed by script (meaning very accurately) around an elliptical path over an Oval of the same geometry, the Loci sit perfectly on the outline of the Oval across a very wide range of zoom levels (100% to 20,000,000%). If as you say, the oval is not displayed "absolutely perfectly", then that would imply the Loci are not displayed "absolutely perfectly" either, and share the same display distortions ovals do. Is this also true? Can you, or your "secret source", elaborate a little more, please? (Hmm – "secret source" – sounds like burger chain jargon. Where is this thread headed?) One moment while I get back on topic... If there is a distortion with the onscreen display, but you can draw Lines between the Loci on the Oval and get proper feedback through the OIP, and/or the Fixed and Floating Data Bars, AND Reshaper, as to their length, angle, dX and dY, and XY positions of their endpoints, AND those values agree with predicted measurements, is there really a distortion we need to worry about? The next thing I fear you'll tell me is the color of ovals on my monitor may be inaccurate. ;-) TIA, Raymond PS - I think the VW Oval should be renamed a Rodney Dangerfield loop, 'cause "it don't get no respect!"
  4. But Pete, you should be able to rely on Lines and Loci being drawn well on VW's cartesian grid at any zoom. About your test, I don't know what you mean by "join a line to the curve", if the curve is an Oval. I am unable to do that, since the oval is a closed object. Do you mean SNAP a line to an Oval or TRIM a Line with an Oval? Trim works, but Snap-to-Object for Ovals does not. I guessed at what you described (using TRIM) and got the opposite results. If you would like, I'd be happy to talk to you on the phone to compare notes and we should both spend my less of our "abundant spare time" on this topic. I'll send you my number offline. All the best, Raymond
  5. Kevin, look more closely. They are not equal, unless you clipped your Oval before comparing it to a Quarter Arc (QA) segment. When unconstrained, the QA tool draws a Polyline, not an Arc, and definitely not a quarter Oval or ellipse. To test if an Oval in VW is an Ellipse, you should plot points by placing Loci at positions determined algebraically from an ellipse formula using the same major and minor axes of a drawn Oval. If done correctly the Loci will perfectly match the Oval's path, showing the Oval to be a real Ellipse in VW. Zoom in to 500,000% and the Loci are still sitting perfectly on the Oval's curve on the screen. Compare that to a QA curve snapped to the same Oval (say, top-center on the oval to right-center on the oval.) The QA curve (now a polyline) is drawn farther out than the curve of the oval / ellipse. Like a trimmed Oval, the unconstrained QA curve can do no better than any other polyline. I'm going back into my hole now. Have fun. Raymond
  6. This conversation was held a decade or so ago on this forum, with the same outcome. Some people believed Ovals are ellipses and some did not. Without going into great detail, the term Oval in VW IS equivalent to the term Ellipse in math circles (or in math ovals, if you will). This can be tested with a script dropping any number of loci evenly around an elliptical path defined by a VW Oval's major and minor axes. For all digital purposes they are equivalent. They agree beautifully. When a VW Oval is clipped, it is converted to a Polyline (a path object). VW Polylines can be composed of any combination of straight, arc, and bezier segments, however it is impossible to exactly represent an ellipse (i.e., a VW Oval), wholly or in part, using these path components. This last statement is based on other people's work. I've read some proofs on this topic and I agree with them. If anyone wants to learn further how to test my statements, please contact me offline. Pete, I didn't use the Oval type above, because that would be the same as using a word in its own definition. As you suggest, it is entirely possible to have an oval's clipped path match a partial ellipse perfectly, but someone will have to submit an enhancement request for a different solution from the existing Polyline conversion, which can never be perfect. VW will need a new object type to achieve this. If a Circle clips to an Arc, perhaps an Oval will clip to an Orc. Forgive me, it's late and I see no obvious term for the requested shape. Let greater minds invent one. HTH, Raymond
  7. Hi Pete, I agree with you that oval segments CAN be represented accurately in a CAD environment, but in VW using the current set of available object types – Line, Arc, Bezier Segment, NURBS – they cannot be represented without some measurable error. There are no VW types available that give an exact equivalence to the Oval type. A series of points along an oval's curve (a Polygon) CAN be made to be as precise as needed (for all practical purposes) but it becomes "point heavy" quickly. Approximating an Oval with Arcs or Bezier segments has been proven by others to be inexact. There are some wonderful papers on the internet describing how to implement these approximations. I've read several and found them fascinating. On the recurring topic of Oval vs. Ellipse, as VW implements the Oval type it performs remarkably well as a perfect ellipse. It's CAD, it's digital, by that very nature it's not exact, but even LINES in CAD have holes in them if you try to specify too many digits. [ This reminds me of a discussion on this board with Petri, some 15 years ago. I do miss his presence still. :-) ] I know many people have their doubts about Oval/Ellipse equivalence in VW. That's okay. I know for what I need they are 100% interchangeable. There's plenty of room for opinions and split hairs here, and I don't need to convince anybody but myself, so we may agree to disagree. Respectfully, Raymond
  8. Donald, There is no exact way to represent a partial piece of an ellipse/oval after it has been trimmed. The path can be approximated by a set of Arcs (as you have seen), Bezier segments, or by a series of short straight Lines (a Polygon if they are connected). Each representation has errors. These can be minimized, but never completely removed. You're absolutely right, it is what it is. Raymond
  9. Black Background doesn't help? It's not as sexy as what Jim posted, but it is easier on the eyes for many types of drawing. I toggle back and forth all the time. Raymond
  10. Sam, You can use GOTO , which causes the execution to jump to the label. GOTO will not jump out of nested procedures, so you'll have to have a and a GOTO at each level to jump to the end of that level when some condition is TRUE. Declare labels at the top of the program or procedure as: LABEL ; EXAMPLE: procedure xyz; Label 88; Begin ... GOTO 88; ... 88: End; { xyz } From the VS Language Guide: The general syntax for a GOTO statement is: GOTO ; GOTO statements have several cautions which must be observed whenever using them: • GOTO statements can only transfer execution within the same procedure, function, or main body of a script. They cannot be used to jump between procedures or between scripts. • The destination of a GOTO statement must always be the beginning of a statement. • Jumping to statements that are contained within the structure of other statements can have undefined effects; the VectorScript compiler will not recognize this action as an error. Raymond
  11. For a script or Plug-in that will toggle the visibility of the WP Axes, see the following post in the "Resource Share - Vectorscript" section of the board. https://techboard.vectorworks.net/ubbthreads.php?ubb=showflat&Number=230437Post230437 Raymond
  12. Last week a question was raised on this board, "Is there a way to hide the display of the axes when working on a rotated plan?" https://techboard.vectorworks.net/ubbthreads.php?ubb=showflat&Number=230007#Post230007 Setting the Interactive Appearance Settings preference "General - Working Plane Axes Opacity" to zero does hide the axes in Rotated Plan View, but it also keeps them off when using the Working Plane tool, where their visibility is more useful. SO - to alleviate the need to manually set the "Working Plane Axes Opacity" preference each time drawing conditions change, I wrote the following script to toggle it between the current setting and zero. If the current setting IS zero the first time the script is run, the script will use a default value of 40%. Subsequent calls will toggle between 40% and 0%. If 40% is not the desired value, simply set the Working Plane Axes Opacity value manually and run the script again to toggle between that new value and zero. The current value is remembered when the script is first run and whenever the value is manually changed. For those who want to use this script as a Plug-in Menu Command, download the attached file and copy it into the Plug-ins folder inside your User Folder, then add it to any workspace. Assigning a hotkey is optional. The Plug-in is compiled in VW 2014 and will also work in subsequent VW versions. PROCEDURE ToggleWPAxes; { Toggle the Working Plane Axes Opacity between 0 and the current value. } { 15 Jul 2016 - Raymond J Mullin } CONST WPAxisOpacity = 1995; { Preference number } PgmName = 'ToggleWPAxes'; { SavedSetting Category name } SubCat = 'Opacity'; { Subcategory name } DefaultOpacity = 40; { any integer value from 1-100% } VAR Val, SavedVal :Integer; function GetSavedWPAxisOpacity(Pgm, Cat :String) :Integer; { return WP Axis Opacity if it is found in the SavedSettings file, else return the Default Opacity } Var Val :Integer; StrVal :String; Begin if GetSavedSetting(Pgm, Cat, StrVal) then begin Val := Str2Num(StrVal); if (Val < 0) then Val := 0 { ensure value is always in proper range } else if (Val > 100) then Val := 100; end else Val := DefaultOpacity; { value has not been stored, use default } GetSavedWPAxisOpacity := Val; End; { GetSavedWPAxisOpacity } BEGIN SavedVal := GetSavedWPAxisOpacity(PgmName, SubCat); Val := GetPrefInt(WPAxisOpacity); { current value } if (Val > 0) & (Val <> SavedVal) then { selective save } SetSavedSetting(PgmName, SubCat, concat(Val)); if (Val = 0) then Val := SavedVal { toggle values } else Val := 0; SetPrefInt(WPAxisOpacity, Val); { apply new value } END; Run(ToggleWPAxes); HTH, Raymond
  13. Howdy Patrick, That's mighty Texan of you ;-) I think you are on the right track with: vs.ForEachObject(). I didn't really look at how you got your "group_center", but you can easily extract a virtual BoundingBox with: X1 = vs.LeftBoundN("All") X2 = vs.RightBoundN("All") Y1 = vs.TopBoundN("All") Y2 = vs.BotBoundN("All") for all objects in the drawing, or use: X1 = vs.LeftBoundN("V") etc., to only process visible objects. then: Xc = (X1 + X2) / 2 Yc = (Y1 + Y2) / 2 (-Xc, -Yc) is the amount you will move everything, assuming the user origin was not moved. Otherwise, you'll have to do the math we did earlier. With different constraints, come different solutions. HTH, Raymond
  14. Martin, I knew the answer to your question was "YES" because my screen doesn't show them, but for the life of me I could not find how I had hidden them. So, after an hour of poking into every dark corner I could find, and there are a lot of them in VW, I started stepping through the Interactive Settings one at a time. When I got down to "General - Working Plane" it hit me like an invisible brick. I had set the "Axes Opacity" to 0. Move that slider all the way to the left. Axes Gone! Of course, they are gone for the Working Plane tool, too. Hope you don't mind. HTH, Raymond
  15. That makes sense. I almost always have "None" as my active class. That's something I would easily miss. Actually, all three scripts will suffer this problem, since they all work pretty much the same way. Nice catch, Patrick. If you want the script to be more fluid, save the active class at the beginning and restore it at the end. Try this expression to see if it works across language lines. vs.NameClass(vs.Index2Name(2)) I am curious if it will return 'Keine' in your version of VW. Please let me know as I cannot test it here. index 2 in the NameList is always "None" and index 3 is always "Dimension" My assumption is that when VW is ported to another language, this call will return "None" in the local language. If it works as I expect, there will be no need comment out lines for different international users. There is another mistake in the 3rd example: V = [-x-y for x,y in zip(Pcen-Orig)] # offset vector V = -Pcen-Orig should read: V = [-x-y for x,y in zip(Pcen, Orig)] # offset vector V = -Pcen-Orig Typo. There should be a comma between the arguments in "zip", and not a minus sign. Raymond
  16. In the previous script I took a more readable approach to presenting the variable elements. In this version I use some of Python's built in functionality. Note: the use of tuples and lists to represent "vectors" and the "zip" function to add the vector elements. In all three versions of this script, if the User Origin is not at the Absolute Origin, this script will adjust for that. # CenterOnOrigin # Moves everything on a design layer to the Origin, # then moves the User Origin to maintain the same XY readings. # 11 Jul 2016 - Raymond J Mullin # USE AT YOUR OWN RISK, and USE on a COPY of your data FIRST! import vs vs.SelectAll() vs.Group() # Orig, Pcen are tuples representing (X,Y) vectors Orig = vs.GetOrigin() Pcen = vs.HCenter(vs.FSActLayer()) V = [-x-y for x,y in zip(Pcen-Orig)] # offset vector V = -Pcen-Orig vs.HMove(vs.FSActLayer(), V[0], V[1]) vs.Ungroup() # optional, to retain the same x&y after the move vs.SetOrigin(V[0], V[1]); # remove to keep drawing center unchanged Raymond
  17. OOPS! This is the Python Scripting Corner. Try this instead: # CenterOnOrigin # Moves everything on a design layer to the Origin, # then moves the User Origin to maintain the same XY readings. # 11 Jul 2016 - Raymond J Mullin # USE AT YOUR OWN RISK, and USE on a COPY of your data FIRST! import vs (OrigX, OrigY) = vs.GetOrigin() vs.SelectAll() vs.Group() (PcenX, PcenY) = vs.HCenter(vs.FSActLayer()) Vx = -PcenX - OrigX Vy = -PcenY - OrigY vs.HMove(vs.FSActLayer(), Vx, Vy) vs.Ungroup() # optional, to retain the same x&y after the move vs.SetOrigin(Vx, Vy); # remove to keep drawing center unchanged Raymond
  18. Patrick, When in doubt, move it yourself. PROCEDURE CenterOnOrigin; { Moves everything on a design layer to the Origin, } { then moves the User Origin to maintain the same XY readings. } { 11 Jul 2016 - Raymond J Mullin } { USE AT YOUR OWN RISK, and USE on a COPY of your data FIRST! } VAR x, y : Real; Orig, Pcen, V :Vector; BEGIN GetOrigin(Orig.x, Orig.y); SelectAll; Group; hCenter(FSActLayer, Pcen.x, Pcen.y); V := -Pcen - Orig; { offset vector } hMove(FSActLayer, V.x, V.y); UnGroup; { optional, to retain the same x&y after the move } SetOrigin(V.x, V.y); { remove to keep drawing center unchanged } END; Run(CenterOnOrigin); Raymond
  19. Hippocode is correct, but his answer may be more complicated than what you need. It is more generic as it applies both to finding points between your endpoints, and also to finding points anywhere along the line passing through your two points. Elaborating on what I posted earlier: The vector V between points P1 and P2 is described as: V := P2 - P1; Its length Norm(V) is the distance between the two points. Its angle Vec2Ang(V) points in the direction from P1 to P2. V2 := V/2; is half as long as the distance from P1 to P2. The direction is the same but the length is half of V. To get the midpoint between P1 and P2 you add V2 to P1.* Similarly, let V3 := V/3; So P1 + V3 is 1/3 the distance between the two points. Similarly V4 := V/4, and P1 + V4 is one quarter the way between the points. Etc. You can add repetitively to get other multiples of points along the line: P1 + V3 is 1/3 from P1 to P2 P1 + V3 + V3 is 2/3 from P1 to P2 P1 + V3 + V3 + V3 is 3/3 from P1 to P2, or at the same position as P2. Elaborating on what Hippocode suggested: What Hippocode is proposing is to make V1 := UnitVec(V). That is, a vector of length 1 and the same direction as V. If you know the length of V (hint: Norm(V)) then you can scale the "unit vector" by any fraction you want, larger or smaller. NewVector := UnitV * OriginalLength * ScaleFactor; Then any new point is P1 + NewVector. Your original vector can be written this way with a scale factor of 1: V := UnitV * OriginalLength * 1; This is the more generic way of thinking about finding points along a line, but it may be more algebra than you need for a simple problem. What you will find is there are usually multiple ways to solve a problem. HTH, Raymond * Another concise way to find the midpoint between two points is: Pmid := (P1 + P2) / 2; It evaluates to the same value as P1 + (P2 - P1) / 2; This expression does not work for finding the 1/3 point, etc.
  20. YES! Vectors scale with multiplication and division by a constant. Vmid := 0.5 * V; or Vmid := V / 2; Same result. It is the same as scaling each component individually: Vmid.x := V.x / 2; Vmid.y := V.y / 2; Vmid.z := V.z / 2; Big time saver when writing code, and it and makes reading it later a lot easier to follow. There are tons of sites on the web about Vector operations. Google and learn. It is very visual so learning is easy. Anyone who can read a map and follow sequential directions already has the basics of Vector arithmetic mastered. Vector math is only a formal way of stating what you already can see spatially. It's an algebraic language, like Pascal, C, and Python are procedural languages, nothing more. Learn the grammar and never look back. Raymond
  21. Michael, Glad I could help. Vectors are easy once you get used to using them. As a data type, think of them as one variable name with three sub-parts: the X, Y, and Z components, or V.x, V.y, and V.z. Usually vectors contain data that is linked in XY or XYZ, but in a program they could contain 3 numbers that do not refer to spatial concepts, like Temperature, Hour, and Minute. You decide what goes in and what comes out. In this case the vector variable is just a convenient wrapper to keep three related values together under one name. For spatial data here are some quick rules to help you think about vectors. • You can store 2D or 3D points in a vector variable. If you store 2D data, just ignore the ".z" component. You can set it to 0, but it probably already is zero. • You can store XY or XYZ displacements in a vector (deltaX, deltaY [, deltaZ]). • If you add or subtract 2 vectors, you'll get a vector as the answer: V3 := V1 + V2; V2 := V3 - V1; { same expression, just rearranged } • if you add a vector and a point, the answer will be another point: P2 := P1 + Voffset; { Voffset is a displacement vector showing where P2 is relative to P1 } • Subtracting 1 point from another point returns a vector showing the displacement between the points: Voffset := P2 - P1; • Adding 2 points is somewhat meaningless, unless you think of their positions as vector displacements from the origin. Another thing to do that helps keep your programs clear is to save data directly to vector fields. Also start vector variable names with a "V" and point variables with a "P". It will help readability. Try this as an example: PROCEDURE xxx; { On a design layer with one Line selected, run script to show the angle and length of the Line. } VAR Ang, Lngth :Real; P1, P2, V :Vector; BEGIN GetSegPt1(FSActLayer, P1.x, P1.y); { starting point of Line } GetSegPt2(FSActLayer, P2.x, P2.y); { ending point of Line } V := P2 - P1; { displacement between points P2 & P1 } Ang := Vec2Ang(V); { angle of vector V } Lngth := Norm(V); { length of vector V } Message('Angle = ', Ang, '° Length = ', Lngth); SysBeep; END; Run(xxx); Welcome to the best part of Vector-scripting. It's all in the name ;-) Raymond
  22. Michael, Are you looking for the slope of the line that connects those points? If so, I think you want to use Vec2Ang(). It's a built-in VS call. Var V :Vector; ... V.x := p2X - p1X; { your DeltaX } V.y := p2Y - p1Y; { your DeltaY } V.z := 0; Ang := Vec2Ang(V); You'll get angles in degrees in the range of +-180. If you want values from 0-360, then test for a negative angle and add 360 to it. if (Ang<0) then Ang := Ang + 360; If you are looking for the angle between two vectors, the answer is a little more complicated, but easily done. Write back for more details. HTH, Raymond
  23. Carl, Try this instead of your function: FUNCTION H_FSActContainer: HANDLE; VAR h : HANDLE; BEGIN h := FIn3D(H_ActContainer); if not Selected(h) THEN h := NextSObj(h); H_FSActContainer := h; END; It may not solve all your problems, but it will return the First Selected Object inside your container. I did not execute your code. I just noticed your WHILE loop would not stop at the first Selected object. This function will return NIL if no objects are selected. HTH, Raymond
  24. Hello Andy, In your calls to SetObjectVariableBoolean() you placed "122" in the slot where a HANDLE variable to the ViewPorts should go. 122 is the type of a VIEWPORT and doesn't point to anything. Since you appear to be new to VectorScript I've attached a short script that demonstrates how to access each VP in your drawing. Use it as an example and modify it to do other tasks. The basic format is the same for many global tasks. Also, read the VS documentation on the set of ForEachObject calls. They are very powerful for walking through a file and selecting objects of interest. PROCEDURE VPProjScreenON; { Set "Project 2D" ON for each ViewPort in the drawing. } CONST Proj2D = True; { True = ON, False = OFF } procedure SetProj2D(H :Handle); Begin SetObjectVariableBoolean(H, 1005, Proj2D); { VP Project 2D } SetObjectVariableBoolean(H, 1035, True); { VP Display Planar } SetDSelect(H); End; { SetProj2D } BEGIN DSelectAll; ForEachObject(SetProj2D, T=VIEWPORT); { do this to each VP in the drawing } END; Run(VPProjScreenON); In this script, the call ForEachObject() gets a handle to each VP, one at a time, and passes it to the procedure SetProj2D(). All the detail work is done in SetProj2D(). Duplicate this program and set the CONSTANT Proj2D to FALSE to make a script that turns the setting OFF. One caveat, this script is only mildly tested. Use at your own risk and start out on a copy of you drawing first. Have Fun, Raymond
  25. Alan, I know very little about Python, but I do know that "print" requires parentheses in Python 3.x. Since you assert it works both ways in your environment, I'd surmise you're running Python 2.x. Based on that, if you use print with parentheses, your "print()" routines should work in both Python 2.x and 3.x environments. If you're only going to work in Python 2.x then you can use whichever form you like. HTH, Raymond
×
×
  • Create New...