yapCAD 0.3.0__py2.py3-none-any.whl → 0.5.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
yapcad/geom.py CHANGED
@@ -73,21 +73,30 @@ coordinates, and was popular with computer graphicists in the
73
73
  In this interpretation, the w coordinate is a normalization
74
74
  coordinate, and is either 1.0 or all coordinates are assumed to be
75
75
  scaled by 1/w. The inclusion of the w coordinate allows the general
76
- use of transformation matrices for affine transforms.
76
+ use of transformation matrices for affine transforms.
77
+
78
+ The exception to the above statement is direction vectors, such as the
79
+ vector ``[1,0,0,0]`` that represents the direction of the x axis.
80
+ Direction vectors live in the ``w=0.0`` plane and are subject to
81
+ rotation and scaling, but not translation.
77
82
 
78
83
  There is a yapcad.geom convenience function, ``vect()``, that will make
79
84
  a vector out of just about any plausible set of arguments. Unspecified
80
85
  w values are set to 1, and unspecified z values are set to 0.
81
86
 
87
+ =========================================
88
+ yapcad.geom simple (non-compound) figures
89
+ =========================================
90
+
82
91
  points
83
92
  ======
84
93
 
85
- Ordinary **yapCAD** geometry is assumed to lie in the w=1 hyperplane, and
86
- when a vector lies in that plane it is usually interpreted as
87
- transformable coordinate, or point. Because we
88
- expect w=1 unless certain types of affine transforms have been
89
- applied, most **yapCAD** geometry operations do not look at the w
90
- coordinate, and operate as though w=1.
94
+ Points are the simplest of the ``yapcad.geom`` figures. Ordinary
95
+ **yapCAD** geometry is assumed to lie in the w=1 hyperplane, and when
96
+ a vector lies in that plane it is usually interpreted as transformable
97
+ coordinate, or point. Because we expect w=1 unless certain types of
98
+ affine transforms have been applied, most **yapCAD** geometry
99
+ operations do not look at the w coordinate, and operate as though w=1.
91
100
 
92
101
  Any vector that lies in the w>0 half-space is a valid coordinate, or
93
102
  point. And in **yapCAD**, ``[x,y,z,w]`` corresponds to the same 3D
@@ -127,11 +136,11 @@ operations. (see below)
127
136
  ----------------
128
137
 
129
138
  One special type of ``yapcad.geom`` line is a 3D bounding box. A
130
- bounding box is a line that spans the "lower bottom left" to "upper
131
- top right" of a figure, *e.g.* ``bbx =
139
+ bounding box is a line that spans the "left lower bottom" to "right
140
+ upper top" of a figure, *e.g.* ``bbx =
132
141
  [[xmin,ymin,zmin,1],[xmax,ymax,zmax,1]]``. Bounding boxes are used
133
- internally to speed up inside testing and for a variety of other
134
- purposes.
142
+ internally to speed up inside/outside testing and for a variety of
143
+ other purposes.
135
144
 
136
145
  arcs
137
146
  ====
@@ -189,6 +198,10 @@ sampling order will have the beneficial property of having the same
189
198
  Arcs support all standard ``yapcad.geom`` computational geometry
190
199
  operations. (see below)
191
200
 
201
+ =========================================
202
+ yapcad.geom compound figures
203
+ =========================================
204
+
192
205
  polylines/polygons
193
206
  ==================
194
207
 
@@ -241,9 +254,9 @@ lists composed of closed elements.
241
254
  Geometry lists are paramaterized a bit like polylines, except that
242
255
  there is no guarantee of continuity.
243
256
 
244
- ======================
245
- COMPUTATIONAL GEOMETRY
246
- ======================
257
+ =================================
258
+ COMPUTATIONAL GEOMETRY OPERATIONS
259
+ =================================
247
260
 
248
261
  The primary purpose of the ``yapcad.geom`` module is to support
249
262
  computational geometry operations on two-dimensional figures in
@@ -461,6 +474,15 @@ def isvect(x):
461
474
  check to see if argument is a proper vector for our purposes
462
475
  """
463
476
  return isinstance(x,list) and len(x) == 4 and isgoodnum(x[0]) and isgoodnum(x[1]) and isgoodnum(x[2]) and isgoodnum(x[3])
477
+
478
+ ## check to see if an argument is a proper direction vector, with w=0
479
+ def isdirect(x):
480
+ return isinstance(x,list) and len(x) == 4 and isgoodnum(x[0]) and isgoodnum(x[1]) and isgoodnum(x[2]) and close(x[3],0.0)
481
+
482
+ ## check to see if argument is a list of direction vectors
483
+ def isdirectlist(xx):
484
+ return len(list(filter(lambda x: not isdirect(x),xx))) == 0
485
+
464
486
 
465
487
  ## R^3 -> R^3 functions: ignore w component
466
488
  ## ------------------------------------------------
@@ -515,6 +537,12 @@ def scale4(a,c):
515
537
  """ 4 vector ``a`` times scalar ``c``"""
516
538
  return [a[0]*c,a[1]*c,a[2]*c,a[3]*c]
517
539
 
540
+ ## component-wise 4vect multiplication
541
+ def mul4(a,b):
542
+ """ component-wise 3 vector multiplication"""
543
+ return [a[0]*b[0],a[1]*b[1],a[2]*b[2],a[3]*b[3]]
544
+
545
+
518
546
  ## Homogenize, or project back to the w=1 plane by scaling all values
519
547
  ## by w
520
548
  def homo(a):
@@ -548,6 +576,13 @@ def isinsidebbox(bbox,p):
548
576
  p[1] >= bbox[0][1] and p[1] <= bbox[1][1] and\
549
577
  p[2] >= bbox[0][2] and p[2] <= bbox[1][2]
550
578
 
579
+ # does point p lie inside 2D bounding box bbox
580
+ def isinsidebbox2D(bbox,p):
581
+ """ does point ``p`` lie inside 2D bounding box ``bbox``?"""
582
+ return ( p[0] >= bbox[0][0] and p[0] <= bbox[1][0] and
583
+ p[1] >= bbox[0][1] and p[1] <= bbox[1][1] )
584
+
585
+
551
586
  # utility function to determine if a list of points lies in the specified
552
587
  # cardinal plane, one of XY, YZ, XZ
553
588
  def isCardinalPlanar(plane="xy",points=[]):
@@ -1800,7 +1835,7 @@ def poly(*args):
1800
1835
  if ispoly(args[0]):
1801
1836
  return deepcopy(args[0])
1802
1837
  else:
1803
- raise VauleError('non-poly list passed to poly()')
1838
+ raise ValueError(f'non-poly list passed to poly(): {args}')
1804
1839
  # args is of length 3 or greater. Check to see if args are points
1805
1840
  a = list(args)
1806
1841
  b = list(filter(lambda x: not ispoint(x),a))
@@ -1838,7 +1873,7 @@ def polycenter(a):
1838
1873
 
1839
1874
  ## we heart poly bboxes
1840
1875
  def polybbox(a):
1841
- """Compute the bounding box of polyline/polygon ``a``"""
1876
+ """Compute the 3D bounding box of polyline/polygon ``a``"""
1842
1877
  if len(a) == 0:
1843
1878
  return False
1844
1879
  elif len(a) == 1:
@@ -1846,9 +1881,11 @@ def polybbox(a):
1846
1881
  else:
1847
1882
  minx = maxx = a[0][0]
1848
1883
  miny = maxy = a[0][1]
1884
+ minz = maxz = a[0][2]
1849
1885
  for i in range(1,len(a)):
1850
1886
  x=a[i][0]
1851
1887
  y=a[i][1]
1888
+ z=a[i][2]
1852
1889
  if x < minx:
1853
1890
  minx =x
1854
1891
  elif x > maxx:
@@ -1857,7 +1894,12 @@ def polybbox(a):
1857
1894
  miny = y
1858
1895
  elif y > maxy:
1859
1896
  maxy = y
1860
- return [ point(minx,miny),point(maxx,maxy)]
1897
+ if z < minz:
1898
+ minz = z
1899
+ elif z > maxz:
1900
+ maxz = z
1901
+
1902
+ return [ point(minx,miny,minz),point(maxx,maxy,maxz)]
1861
1903
 
1862
1904
  ## only valid for closed polylines. Count the intersections for a
1863
1905
  ## line drawn from point to test to a point outside the bounding
@@ -2111,9 +2153,24 @@ def intersectSimplePolyXY(g,a,inside=True,params=False):
2111
2153
 
2112
2154
 
2113
2155
  def polycenter(a):
2114
- return samplepoly(a,0.5)
2156
+ """Compute center of poly ``a``. If ``a`` is closed, return
2157
+ barycentric center of figure. If ``a`` is not closed, return
2158
+ sampling midpoint.
2159
+
2160
+ """
2161
+ if ispolygon(a):
2162
+ avg = a[0]
2163
+ l = len(a)-1
2164
+ for i in range(1,l):
2165
+ avg = add(a[i],avg)
2166
+ return scale3(avg,1.0/l)
2167
+ else:
2168
+ return sample(a,0.5)
2115
2169
 
2116
2170
  def polylength(a):
2171
+ """
2172
+ compute length of poly ``a``
2173
+ """
2117
2174
  if len(a) < 2:
2118
2175
  return 0.0
2119
2176
  l = 0.0
@@ -2127,6 +2184,9 @@ def polylength(a):
2127
2184
  ## or other geometry lists.
2128
2185
 
2129
2186
  def isgeomlist(a):
2187
+ """
2188
+ determine if argument ``a`` is a valid geometry list
2189
+ """
2130
2190
  if not isinstance(a,list):
2131
2191
  return False
2132
2192
  b = list(filter(lambda x: not (ispoint(x) or isline(x) \
@@ -2135,6 +2195,43 @@ def isgeomlist(a):
2135
2195
  return not len(b) > 0
2136
2196
 
2137
2197
 
2198
+ def iscontinuousgeomlist(a):
2199
+ """
2200
+ deterine if geometry list ``a`` posesses C0 continuity over sampling
2201
+ interval [0.0,1.0].
2202
+ """
2203
+ l = len(a)
2204
+ if l < 2:
2205
+ return True
2206
+ for i in range(1,l):
2207
+ x1 = sample(a[i-1],1.0)
2208
+ x2 = sample(a[i],0.0)
2209
+ if not vclose(x1,x2):
2210
+ #print(f"l: {l}, a: {vstr(a)}")
2211
+ #print(f"i: {i} dist(x1,x2): {dist(x1,x2)}")
2212
+ return False
2213
+ return True
2214
+
2215
+ def isclosedgeomlist(a):
2216
+ """Determine if geometry list ``a`` is closed, which is to say
2217
+ determine if the geometry list is continuous and the distance
2218
+ between ``sample(a,0.0)`` and ``sample(a,1.0)`` is less than
2219
+ epsilon. *NOTE:* This test will not detemrine if this geometry
2220
+ list representes a simple closed figure as there could be any
2221
+ number of self intersections.
2222
+
2223
+ *NOTE:* The special case of ``a==[]`` will cause
2224
+ ``isclosedgeomlist(a)`` to return ``True``, so that set operations
2225
+ such as intersection or difference operations which return an
2226
+ empty result will still be considered valid closed geometry for
2227
+ further operations.
2228
+
2229
+ """
2230
+ return (a == [] or (
2231
+ iscontinuousgeomlist(a) and
2232
+ vclose(sample(a,0.0),sample(a,1.0))))
2233
+
2234
+
2138
2235
  def __geomlistlength(gl):
2139
2236
  leng=0.0
2140
2237
  lengths=[]
@@ -2169,6 +2266,46 @@ def samplegeomlist(gl,u):
2169
2266
  uu = (dst-leng+lengths[-1])/lengths[-1]
2170
2267
  return sample(gl[-1],uu)
2171
2268
 
2269
+
2270
+ def unsamplegeomlist(gl,p):
2271
+ """
2272
+ anlogous to the unsampleline() and unsamplearc() functions, given a
2273
+ point on a poly, return the corresponding sample parameter, or
2274
+ False if the point is more than epsilon away from any poly line
2275
+ segment
2276
+ """
2277
+ if not isgeomlist(g):
2278
+ raise ValueError('non geometry list passed to unsamplegeomlist')
2279
+
2280
+ lengths,leng = __geomlistlength(gl)
2281
+ if len(gl) == 1:
2282
+ return unsample(gl[0],p)
2283
+ else:
2284
+ uu1 = unsample(gl[0],p)
2285
+ if (not isinstance(uu1,bool)
2286
+ and uu1 < 1.0 and uu1 >= 0.0):
2287
+ return uu1*lengths[0]/leng
2288
+ dst = lengths[0]
2289
+ if len(gl) > 2:
2290
+ for i in range(1,len(gl)-1):
2291
+ if lengths[i] <= epsilon:
2292
+ continue
2293
+ uu = unsample(gl[i],p)
2294
+ if (not isinstance(uu,bool)
2295
+ and uu >= 0.0 and uu < 1.0):
2296
+ return (uu*lengths[i]+dst)/length
2297
+ else:
2298
+ dst = dst+lengths[i]
2299
+ uu2 = unsample(gl[-1],p)
2300
+
2301
+ if (not isinstance(uu2,bool) and
2302
+ uu2 >= 0.0 and uu2 <= 1.0):
2303
+ return (uu2*lengths[-1]+dst)/length
2304
+ else:
2305
+ return False
2306
+
2307
+
2308
+
2172
2309
  ## function to reverse a geometry list (presumably contiguous) for
2173
2310
  ## sampling purposes
2174
2311
  def reverseGeomList(gl):
@@ -2230,6 +2367,8 @@ def segmentgeomlist(gl,u1,u2,closed=False,reverse=False):
2230
2367
 
2231
2368
  for i in range(len(gl)):
2232
2369
  l=lengths[i]
2370
+ if l < epsilon:
2371
+ continue
2233
2372
  if dst1 <= d+l:
2234
2373
  if not STARTED:
2235
2374
  uu = 1.0 - (d+l-dst1)/l
@@ -2315,7 +2454,7 @@ def isgeomlistXYPlanar(gl):
2315
2454
  return False
2316
2455
  return isXYPlanar(pp)
2317
2456
 
2318
- ## compute the intersection between geometric element g, and geometry
2457
+ ## compute the intersection between coplanar geometric element g, and geometry
2319
2458
  ## list gl. NOTE: this function does not impose continuity
2320
2459
  ## requirements on the geometry list, and point elements are ignored
2321
2460
  ## for intersection testing.
@@ -2541,7 +2680,9 @@ def center(x):
2541
2680
  pl = []
2542
2681
  for g in x:
2543
2682
  pl.append(center(g))
2544
- return center(pl)
2683
+ if isclosedgeomlist(x):
2684
+ pl.append(pl[0])
2685
+ return polycenter(pl)
2545
2686
  else:
2546
2687
  raise ValueError("inappropriate type for center(): ",format(x))
2547
2688
 
@@ -2602,7 +2743,7 @@ def unsample(x,p):
2602
2743
  elif ispoly(x):
2603
2744
  return unsamplepoly(x,p)
2604
2745
  elif isgeomlist(x):
2605
- raise NotImplementedError('unsampling geometry lists currently not supported')
2746
+ return unsamplegeomlist(x,p)
2606
2747
  else:
2607
2748
  raise ValueError("inappropriate type for unasample(): "+str(x))
2608
2749
 
@@ -2624,10 +2765,13 @@ def segment(x,u1,u2):
2624
2765
  else:
2625
2766
  raise ValueError("inappropriate figure type for segment(): "+str(x))
2626
2767
 
2627
-
2628
-
2629
-
2630
2768
  def isinsideXY(x,p):
2769
+ """for an XY-coplanar point and figure, determine if the point lies
2770
+ inside the figure. In the case of non-closed figures, such as
2771
+ lines, determine if the point lies within epsilon of one of the
2772
+ lines of the figure.
2773
+
2774
+ """
2631
2775
  if ispoint(x):
2632
2776
  return isinsidepointXY(x,p)
2633
2777
  elif isline(x):
@@ -2642,6 +2786,7 @@ def isinsideXY(x,p):
2642
2786
  raise ValueError("bad thing passed to inside: {}".format(x))
2643
2787
 
2644
2788
  def translate(x,delta):
2789
+ """ return a translated version of the figure"""
2645
2790
  if ispoint(x):
2646
2791
  return add(x,delta)
2647
2792
  elif isline(x):
@@ -2664,6 +2809,7 @@ def translate(x,delta):
2664
2809
  raise ValueError("don't know how to translate {}".format(x))
2665
2810
 
2666
2811
  def scale(x,sx=1.0,sy=False,sz=False,cent=point(0,0),mat=False):
2812
+ """ return a scaled version of the figure"""
2667
2813
  if sy == False and sz == False:
2668
2814
  sy = sz = sx
2669
2815
  if vclose(point(sx,sy,sz),point(1.0,1.0,1.0)):
@@ -2706,6 +2852,8 @@ def scale(x,sx=1.0,sy=False,sz=False,cent=point(0,0),mat=False):
2706
2852
 
2707
2853
 
2708
2854
  def transform(x,m):
2855
+ """ return a transformed version of the figure, as specified by the
2856
+ transformation matrix m"""
2709
2857
  if not isinstance(m,xform.Matrix):
2710
2858
  raise ValueError('bad transformation matrix passed to transform')
2711
2859
  if ispoint(x):
@@ -2737,20 +2885,21 @@ def transform(x,m):
2737
2885
  # recursive processing of geometry lists.
2738
2886
 
2739
2887
  def rotate(x,ang,cent=point(0,0),axis=point(0,0,1.0),mat=False):
2888
+ """ return a rotated version of the figure"""
2740
2889
  if close(ang,0.0):
2741
2890
  return deepcopy(x)
2742
2891
  if not mat: # if matrix isn't pre-specified, calculate it
2743
2892
  if vclose(cent,point(0,0,0)):
2744
2893
  mat = xform.Rotation(axis,ang)
2745
2894
  else:
2746
- mat = xform.Translation(cent,inverse=True)
2895
+ mat = xform.Translation(cent)
2747
2896
  mat = mat.mul(xform.Rotation(axis,ang))
2748
- mat = mat.mul(xform.Translation(cent))
2897
+ mat = mat.mul(xform.Translation(cent,inverse=True))
2749
2898
 
2750
2899
  # arcs are wierd, since we will have to deal with a non-trivial
2751
2900
  # change of basis function to handle the interpretation of "start"
2752
2901
  # and "end" if the axis of rotation isn't the z axis.
2753
- if ispoint(x):
2902
+ if ispoint(x) or isvect(x):
2754
2903
  return mat.mul(x)
2755
2904
  elif isline(x):
2756
2905
  return line(mat.mul(x[0]),
@@ -2765,7 +2914,7 @@ def rotate(x,ang,cent=point(0,0),axis=point(0,0,1.0),mat=False):
2765
2914
  c[1][2] += ang
2766
2915
  return c
2767
2916
 
2768
- elif isgeomlist(x):
2917
+ elif isgeomlist(x) or isdirectlist(x):
2769
2918
  gl = []
2770
2919
  for g in x:
2771
2920
  gl.append(rotate(g,ang,cent,axis,mat))
@@ -2778,7 +2927,16 @@ def rotate(x,ang,cent=point(0,0),axis=point(0,0,1.0),mat=False):
2778
2927
  ## generalized geometry mirror function
2779
2928
 
2780
2929
  def mirror(x,plane):
2781
- flip=point(1,1,1)
2930
+ """
2931
+ return a mirrored version of a figure. Currently, the following
2932
+ values of "plane" are allowed: 'xz', 'yz', xy'. Generalized
2933
+ arbitrary reflection plane specification will be added in the
2934
+ future.
2935
+
2936
+ NOTE: this operation will reverse the sign of the area of ``x`` if
2937
+ x is a closed polyline or geometry list
2938
+ """
2939
+ flip=[1,1,1,1]
2782
2940
  if plane == 'xz':
2783
2941
  flip[1]= -1
2784
2942
  elif plane == 'yz':
@@ -2788,8 +2946,8 @@ def mirror(x,plane):
2788
2946
  else:
2789
2947
  raise ValueError('bad reflection plane passed to mirror')
2790
2948
 
2791
- if ispoint(x):
2792
- return point(mul(x,flip))
2949
+ if isvect(x):
2950
+ return mul4(x,flip)
2793
2951
  elif isarc(x):
2794
2952
  a2=arc(x)
2795
2953
  a2[0] = mul(x[0],flip)
@@ -2806,10 +2964,10 @@ def mirror(x,plane):
2806
2964
  a2[1][1]=start
2807
2965
  a2[1][2]=end
2808
2966
  return a2
2809
- elif ispoly(x):
2967
+ elif ispoly(x) or isdirectlist(x):
2810
2968
  ply = []
2811
2969
  for p in x:
2812
- ply.append(mul(p,flip))
2970
+ ply.append(mul4(p,flip))
2813
2971
  return ply
2814
2972
  elif isgeomlist(x):
2815
2973
  r = []
@@ -2829,6 +2987,7 @@ def mirror(x,plane):
2829
2987
  ## if no intersections
2830
2988
 
2831
2989
  def _intersectSimpleXY(g1,g2,inside=True,params=False):
2990
+ """non-value-safe function that determines the intersection of two XY-coplanar non-compound geometric figures"""
2832
2991
  g1line = True
2833
2992
  g2line = True
2834
2993
  if isarc(g1):
@@ -2859,6 +3018,7 @@ def _intersectSimpleXY(g1,g2,inside=True,params=False):
2859
3018
  ## Value-safe simple wrapper for calculation of intersection of
2860
3019
  ## non-compound geometric elements
2861
3020
  def intersectSimpleXY(g1,g2,inside=True,params=False):
3021
+ """value-safe function that determines the intersection of two XY-coplanar non-compound geometric figures"""
2862
3022
  if not (isline(g1) or isarc(g1)) \
2863
3023
  or not (isline(g2) or isarc(g2)):
2864
3024
  raise ValueError('bad geometry passed to intersectSimpleXY')
@@ -2870,6 +3030,7 @@ def intersectSimpleXY(g1,g2,inside=True,params=False):
2870
3030
 
2871
3031
  ## is the argument a "simple" (non-compound) geometry object
2872
3032
  def issimple(g):
3033
+ """ determine if the argument is a simple (non-compound) figure"""
2873
3034
  if ispoint(g) or isline(g) or isarc(g):
2874
3035
  return True
2875
3036
  else:
@@ -2880,6 +3041,16 @@ def issimple(g):
2880
3041
  ## intersection. Booo-ya.
2881
3042
 
2882
3043
  def intersectXY(g1,g2,inside=True,params=False):
3044
+ """
3045
+ given two XY-coplanar figures, calculate the intersection of these
3046
+ two figures, and return a list of intersection points, or False if
3047
+ none. If ``inside == True``, only return intersections that are
3048
+ within the ``0 <= u <= 1.0`` interval for both figures. If
3049
+ ``params == True``, instead of returning a list of points, return
3050
+ two lists corresponding to the sampling parameter value of the
3051
+ intersections corresponding to each figure.
3052
+
3053
+ """
2883
3054
  if ispoint(g1) or ispoint(g2):
2884
3055
  return False
2885
3056
  elif issimple(g1):
@@ -2960,234 +3131,3 @@ def intersectXY(g1,g2,inside=True,params=False):
2960
3131
  else:
2961
3132
  raise ValueError('very bad thing, this should never happen')
2962
3133
 
2963
-
2964
-
2965
-
2966
-
2967
-
2968
-
2969
- ## UNIT TESTS
2970
- ## ========================================
2971
- ## check to see if we have been invoked on the command line
2972
- ## if so, run some tests
2973
-
2974
- if __name__ == "__main__":
2975
- print("------------------------------------------")
2976
- print("yapCAD geometry tests")
2977
- print("------------------------------------------")
2978
- print("light-weight unit tests for geom.py module")
2979
- a = point(5,0)
2980
- b = point(0,5)
2981
- c = point(-3,-3)
2982
- d = point(1,1)
2983
- e = point(10,10)
2984
- # print("---> point creation and testing")
2985
- # print("some points: a:" + vstr(a) + ", b:"
2986
- # + vstr(b) + ", c:" + vstr(c) + ", d:" + vstr(d) + ", e:" + vstr(e))
2987
- # print("ispoint(a): ",ispoint(a))
2988
- # print("ispoint(point(a)): ",ispoint(point(a)))
2989
- # print("ispoint([1,2]: ",ispoint([1,2]))
2990
- # print("ispoint(vect(1,2)): ",ispoint(vect(1,2)))
2991
- # print("ispoint(vect(1,2,3,4)): ",ispoint(vect(1,2,3,4)))
2992
- # print("ispoint(vect(1,2,3,-1)): ",ispoint(vect(1,2,3,-1)))
2993
-
2994
- print("---> basic vector operations tests")
2995
- # print("mag a: " + str(mag(a)))
2996
- # print("add(a,b): " + vstr(add(a,b)))
2997
- # print("sub(a,b): " + vstr(sub(a,b)))
2998
- # print("mag(sub(a,b)): " + str(mag(sub(a,b))))
2999
- # print("mag(sub(a,b)) == sqrt(50): " + str(mag(sub(a,b))==sqrt(50.0)))
3000
-
3001
- print("---> line creation and testing")
3002
- l1 = [a,b]
3003
- # print("l1 = [a,b] -- l1:",vstr(l1))
3004
- # l11 = line(a,b)
3005
- # print("l11 = line(a,b) -- l1:",vstr(l11))
3006
- l2 = [c,d]
3007
- # l22 = line(l2)
3008
- # print("l2 = [c,d], l22 = line(l2) -- l22: ",vstr(l22))
3009
- l3 = line(c,e)
3010
- # print("l3 = line(c,e), isline(l3) : ",isline(l3))
3011
- # print("a {}, isline(a): {}".format(vstr(a),isline(a)))
3012
-
3013
-
3014
- print("---> vector and geometry copying tests")
3015
- foo = [a,b,l3,l2,d]
3016
- print("foo: ",vstr(foo))
3017
- print("deepcopy(foo)",vstr(deepcopy(foo)))
3018
- bar = [a,b,[1,2],l2,l3]
3019
- print("bar: ",vstr(bar))
3020
- print("expect False: deepcopy(bar)",vstr(deepcopy(bar)))
3021
-
3022
- print("---> line-line intersection tests")
3023
- # print("l1:" + vstr(l1) + ", l2:" + vstr(l2) +", l3:" + vstr(l3))
3024
-
3025
- # int0 = lineLineIntersectXY(l1,l1)
3026
- # int1 = lineLineIntersectXY(l1,l2,False)
3027
- # int2 = lineLineIntersectXY(l1,l2,True)
3028
- # int3 = lineLineIntersectXY(l1,l3,True)
3029
-
3030
- # print("expect False: lineLineIntersectXY(l1,l1): " + vstr(int0))
3031
- # print("expect [2.5, 2.5]: lineLineIntersectXY(l1,l2,False): " + vstr(int1))
3032
- # print("expect False: lineLineIntersectXY(l1,l2,True): " + vstr(int2))
3033
- # print("expect [2.5, 2.5]: lineLineIntersectXY(l1,l3,True): " + vstr(int3))
3034
-
3035
- # print("linePointXY(l1,vect(0,0)): "
3036
- # + vstr(linePointXY(l1,vect(0,0))))
3037
- # print("linePointXYDist(l1,vect(0,0)) == sqrt(12.5): "
3038
- # + vstr(abs(linePointXYDist(l1,vect(0,0))-sqrt(12.5))<epsilon))
3039
- # print("linePointXY(l1,vect(0,10),False): "
3040
- # + vstr(linePointXY(l1,vect(vect(0,10)),False)))
3041
- # print("linePointXY(l1,vect(0,10),True): "
3042
- # + vstr(linePointXY(l1,vect(0,10),True)))
3043
- # print("linePointXY(l1,vect(10,0),False): "
3044
- # + vstr(linePointXY(l1,vect(10,0),False)))
3045
- # print("linePointXY(l1,vect(10,0),True): "
3046
- # + vstr(linePointXY(l1,vect(10,0),True)))
3047
-
3048
- print("---> arc creation and testing")
3049
- # arc1=[vect(2.5,2.5),vect(2.5,90.0,270.0,-1)]
3050
- # print("arc1=[vect(2.5,2.5),vect(2.5,90.0,270.0,-1)], arc1: ",vstr(arc1))
3051
- # arc11=arc(vect(2.5,2.5),2.5,90.0,270.0)
3052
- # print("arc11=arc(vect(2.5,2.5),2.5,90.0,270.0), arc11: ",vstr(arc11))
3053
- # print("isarc(arc1): {} isarc(arc11): {}".format(isarc(arc1),isarc(arc11)))
3054
- # arc12=arc(arc11)
3055
- # print("arc12=arc(arc11), arc12: {}, isarc(arc12): {}".format(vstr(arc12),isarc(arc12)))
3056
- # try:
3057
- # print("try creating an arc with a negative radius, should raise ValueError")
3058
- # print("arc(vect(0,0),-2): ",arc(vect(0,0),-2))
3059
- # except ValueError as err:
3060
- # print('got expected result:',err)
3061
- # print("--> line-arc disambiguation")
3062
- # print("l1: ",vstr(l1)," arc1: ",vstr(arc1))
3063
- # print("isline(l1): {} isline(arc1): {}".format(isline(l1),isline(arc1)))
3064
- # print("isarc(l1): {} isarc(arc1): {}".format(isarc(l1),isarc(arc1)))
3065
- # print("---> arc-line intersection tests")
3066
- arc1=[vect(2.5,2.5),vect(2.5,90.0,270.0)]
3067
- print("arc1: {}".format(vstr(arc1)))
3068
- print("l1: {}".format(vstr(l1)))
3069
- l2[1]=vect(0,0)
3070
- print("l2: {}".format(vstr(l2)))
3071
- int4 = lineArcIntersectXY(l1,arc1,False)
3072
- int5 = lineArcIntersectXY(l1,arc1,True)
3073
- int6 = lineArcIntersectXY([vect(0,5),vect(5,5)],arc1,True)
3074
- int7 = lineArcIntersectXY(l2,arc1,True)
3075
- int8 = lineArcIntersectXY(l2,arc1,False)
3076
- print("lineArcIntersectXY(l1,arc1,False): {}".format(vstr(int4)))
3077
- print("lineArcIntersectXY(l1,arc1,True): {}".format(vstr(int5)))
3078
- print("lineArcIntersectXY([vect(0,5),vect(5,5)],arc1,True): {}".format(vstr(int6)))
3079
- print("lineArcIntersectXY(l2,arc1,False): {}".format(vstr(int7)))
3080
- print("lineArcIntersectXY(l2,arc1,True): {}".format(vstr(int8)))
3081
-
3082
- print("---> circle-circle tangent testing")
3083
- circ1 = arc(point(5,5),5)
3084
- circ2 = arc(point(-5,5),7.5)
3085
- circ3 = arc(point(0,0),1)
3086
-
3087
- tl1 = circleCircleTangentsXY(circ1,circ2)
3088
- tl2 = circleCircleTangentsXY(circ2,circ1)
3089
- tl3 = circleCircleTangentsXY(circ3,circ2)
3090
-
3091
- print("circ1: ",vstr(circ1))
3092
- print("circ2: ",vstr(circ2))
3093
- print("circ3: ",vstr(circ3))
3094
-
3095
- print("circleCircleTangentsXY(circ1,circ2) :", vstr(tl1))
3096
- print("circleCircleTangentsXY(circ2,circ1) :", vstr(tl2))
3097
- print("circleCircleTangentsXY(circ3,circ2) :", vstr(tl3))
3098
-
3099
- print("---> arc-arc intersection tests")
3100
- arc2=[vect(4.0,2.5),vect(2.5,90.0,270.0)]
3101
- print("arc1: {}".format(vstr(arc1)))
3102
- print("arc2: {}".format(vstr(arc2)))
3103
-
3104
- int9 = arcArcIntersectXY(arc1,arc2,False)
3105
- int10 = arcArcIntersectXY(arc1,arc2,True)
3106
- int11 = arcArcIntersectXY(arc2,arc1,True)
3107
- print("arcArcIntersectXY(arc1,arc2,False):",vstr(int9))
3108
- print("arcArcIntersectXY(arc1,arc2,True):",vstr(int10))
3109
- print("arcArcIntersectXY(arc2,arc1,True):",vstr(int11))
3110
-
3111
-
3112
- print("---> do some planar point testing")
3113
- # points in the x-y plane
3114
- p1 = point(2.5,0)
3115
- p2 = point(5,5)
3116
- p3 = point(0,5)
3117
- p4 = point(2.5,10)
3118
-
3119
- # points in the x,z plane
3120
- p5 = point(1,0,-5)
3121
- p6 = point(10,0,10)
3122
-
3123
- # points in the y-z plane
3124
- p7 = point(0,2,-1)
3125
- p8 = point(0,10,10)
3126
-
3127
- print('expect True: isCardinalPlanar("xy",[p1,p2,p3,p4]) : {}'.format(
3128
- isCardinalPlanar("xy",[p1,p2,p3,p4])))
3129
- print('expect False: isCardinalPlanar("xz",[p1,p2,p3,p4]) : {}'.format(
3130
- isCardinalPlanar("xz",[p1,p2,p3,p4])))
3131
- print('expect False: isCardinalPlanar("yz",[p1,p2,p3,p4]) : {}'.format(
3132
- isCardinalPlanar("yz",[p1,p2,p3,p4])))
3133
-
3134
- print('expect True: isCardinalPlanar("xz",[p1,p5,p6]) : {}'.format(
3135
- isCardinalPlanar("xz",[p1,p5,p6])))
3136
-
3137
- print('expect True: isCardinalPlanar("yz",[p3,p7,p8]) : {}'.format(
3138
- isCardinalPlanar("yz",[p3,p7,p8])))
3139
-
3140
- try:
3141
- print('deliberate bad plane specification, should raise ValueError')
3142
- print('isCardinalPlanar("FOO!",[p1,p2,p3,p4]) : {}'.format(
3143
- isCardinalPlanar("FOO!",[p1,p2,p3,p4])))
3144
- except ValueError as err:
3145
- print('got expected result:',err)
3146
-
3147
-
3148
- print("---> convex polygon inside testing")
3149
- tri1 = [p1,p2,p3]
3150
- poly1 = [p1,p2,p4,p3]
3151
- p = point(2.5,1.0)
3152
- q = point(2.5,5.0)
3153
- r = point(2.5,7.0)
3154
- s= point(-10,-10)
3155
- t= point(10,10)
3156
- print ("p: {}, q: {}, r: {}, s: {}, t: {}".format(vstr(p), vstr(q),
3157
- vstr(r), vstr(s),
3158
- vstr(t)))
3159
- print ("tri1: {}".format(vstr(tri1)))
3160
- print ("ispoly(tri1): ",ispoly(tri1))
3161
- print ("istriangle(tri1): ",istriangle(tri1))
3162
- print("expect True: isInsideTriangleXY(p,tri1): {}"\
3163
- .format(isInsideTriangleXY(p,tri1)))
3164
- print("expect True: isInsideTriangleXY(q,tri1): {}"\
3165
- .format(isInsideTriangleXY(q,tri1)))
3166
- print("expect False: isInsideTriangleXY(r,tri1): {}"\
3167
- .format(isInsideTriangleXY(r,tri1)))
3168
- print("expect False: isInsideTriangleXY(s,tri1): {}"\
3169
- .format(isInsideTriangleXY(s,tri1)))
3170
- print("expect False: isInsideTriangleXY(t,tri1): {}"\
3171
- .format(isInsideTriangleXY(t,tri1)))
3172
- print("inside poly testing")
3173
- print ("tri1: {}".format(vstr(tri1)))
3174
- print ("poly1: {}".format(vstr(poly1)))
3175
- print("expect True: isInsideConvexPolyXY(p,tri1): {}"\
3176
- .format(isInsideConvexPolyXY(p,tri1)))
3177
- print("expect True: isInsideConvexPolyXY(q,tri1): {}"\
3178
- .format(isInsideConvexPolyXY(q,tri1)))
3179
- print("expect False: isInsideConvexPolyXY(r,tri1): {}"\
3180
- .format(isInsideConvexPolyXY(r,tri1)))
3181
-
3182
- print("expect True: isInsideConvexPolyXY(p,poly1): {}"\
3183
- .format(isInsideConvexPolyXY(p,poly1)))
3184
- print("expect True: isInsideConvexPolyXY(q,poly1): {}"\
3185
- .format(isInsideConvexPolyXY(q,poly1)))
3186
- print("expect True: isInsideConvexPolyXY(r,poly1): {}"\
3187
- .format(isInsideConvexPolyXY(r,poly1)))
3188
- print("expect False: isInsideConvexPolyXY(s,tri1): {}"\
3189
- .format(isInsideConvexPolyXY(s,tri1)))
3190
- print("expect False: isInsideConvexPolyXY(t,tri1): {}"\
3191
- .format(isInsideConvexPolyXY(t,tri1)))
3192
-
3193
- print("done!")