bspy 2.2.2__py3-none-any.whl → 3.0.1__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.
@@ -17,7 +17,7 @@ def add(self, other, indMap = None):
17
17
  otherMapped = []
18
18
  otherToSelf = {}
19
19
  if indMap is not None:
20
- (self, other) = self.common_basis((other,), indMap)
20
+ (self, other) = bspy.Spline.common_basis((self, other), indMap)
21
21
  for map in indMap:
22
22
  selfMapped.append(map[0])
23
23
  otherMapped.append(map[1])
@@ -57,7 +57,7 @@ def add(self, other, indMap = None):
57
57
  # Reverse the permutation.
58
58
  coefs = coefs.transpose(np.argsort(permutation))
59
59
 
60
- return type(self)(nInd, self.nDep, order, nCoef, knots, coefs, self.accuracy + other.accuracy, self.metadata)
60
+ return type(self)(nInd, self.nDep, order, nCoef, knots, coefs, self.metadata)
61
61
 
62
62
  def confine(self, range_bounds):
63
63
  if self.nInd != 1: raise ValueError("Confine only works on curves (nInd == 1)")
@@ -100,6 +100,15 @@ def confine(self, range_bounds):
100
100
  for i in range(spline.nDep):
101
101
  intersectBoundary(i, 0)
102
102
  intersectBoundary(i, 1)
103
+
104
+ # Put the intersection points in order.
105
+ intersections.sort(key=lambda intersection: intersection[0])
106
+
107
+ # Remove repeat points at start and end.
108
+ if intersections[1][0] - intersections[0][0] < epsilon:
109
+ del intersections[1]
110
+ if intersections[-1][0] - intersections[-2][0] < epsilon:
111
+ del intersections[-2]
103
112
 
104
113
  # Insert order-1 knots at each intersection point.
105
114
  for (knot, boundaryPoint, headedOutside) in intersections:
@@ -110,9 +119,6 @@ def confine(self, range_bounds):
110
119
  spline = spline.insert_knots(([knot] * count,))
111
120
  else:
112
121
  spline = spline.insert_knots(([knot] * (order - 1),))
113
-
114
- # Put the intersection points in order.
115
- intersections.sort(key=lambda intersection: intersection[0])
116
122
 
117
123
  # Go through the boundary points, assigning boundary coefficients, interpolating between boundary points,
118
124
  # and removing knots and coefficients where the curve stalls.
@@ -194,7 +200,7 @@ def contract(self, uvw):
194
200
  else:
195
201
  ix += 1
196
202
 
197
- return type(self)(nInd, self.nDep, order, nCoef, knots, coefs, self.accuracy, self.metadata)
203
+ return type(self)(nInd, self.nDep, order, nCoef, knots, coefs, self.metadata)
198
204
 
199
205
  def cross(self, vector):
200
206
  if isinstance(vector, bspy.Spline):
@@ -206,14 +212,14 @@ def cross(self, vector):
206
212
  coefs[0] = vector[2] * self.coefs[1] - vector[1] * self.coefs[2]
207
213
  coefs[1] = vector[0] * self.coefs[2] - vector[2] * self.coefs[0]
208
214
  coefs[2] = vector[1] * self.coefs[0] - vector[0] * self.coefs[1]
209
- return type(self)(self.nInd, 3, self.order, self.nCoef, self.knots, coefs, self.accuracy, self.metadata)
215
+ return type(self)(self.nInd, 3, self.order, self.nCoef, self.knots, coefs, self.metadata)
210
216
  else:
211
217
  if not(self.nDep == 2): raise ValueError("Invalid nDep")
212
218
  if not(len(vector) == self.nDep): raise ValueError("Invalid vector")
213
219
 
214
220
  coefs = np.empty((1, *self.coefs.shape[1:]), self.coefs.dtype)
215
221
  coefs[0] = vector[1] * self.coefs[0] - vector[0] * self.coefs[1]
216
- return type(self)(self.nInd, 3, self.order, self.nCoef, self.knots, coefs, self.accuracy, self.metadata)
222
+ return type(self)(self.nInd, 3, self.order, self.nCoef, self.knots, coefs, self.metadata)
217
223
 
218
224
  def differentiate(self, with_respect_to = 0):
219
225
  if not(0 <= with_respect_to < self.nInd): raise ValueError("Invalid with_respect_to")
@@ -237,7 +243,7 @@ def differentiate(self, with_respect_to = 0):
237
243
  alpha = degree / (dKnots[i+degree] - dKnots[i])
238
244
  newCoefs[i] = alpha * (newCoefs[i] - oldCoefs[i])
239
245
 
240
- return type(self)(self.nInd, self.nDep, order, nCoef, knots, newCoefs.swapaxes(0, with_respect_to + 1), self.accuracy, self.metadata)
246
+ return type(self)(self.nInd, self.nDep, order, nCoef, knots, newCoefs.swapaxes(0, with_respect_to + 1), self.metadata)
241
247
 
242
248
  def dot(self, vector):
243
249
  if isinstance(vector, bspy.Spline):
@@ -250,24 +256,24 @@ def dot(self, vector):
250
256
  coefs += vector[i] * self.coefs[i]
251
257
  if len(coefs.shape) == len(self.coefs.shape) - 1:
252
258
  coefs = coefs.reshape(1, *coefs.shape)
253
- return type(self)(self.nInd, 1, self.order, self.nCoef, self.knots, coefs, self.accuracy, self.metadata)
259
+ return type(self)(self.nInd, 1, self.order, self.nCoef, self.knots, coefs, self.metadata)
254
260
 
255
261
  def graph(self):
256
262
  self = self.clamp(range(self.nInd), range(self.nInd))
257
263
  coefs = np.insert(self.coefs, self.nInd * (0,), 0.0, axis = 0)
258
264
  for nInd in range(self.nInd):
259
265
  dep = np.swapaxes(coefs, nInd + 1, 1)[nInd] # Returns a view, so changes to dep make changes to coefs
260
- for i, knotAvg in enumerate(self.greville(nInd)):
261
- dep[i] = knotAvg
262
- return type(self)(self.nInd, self.nInd + self.nDep, self.order, self.nCoef, self.knots, coefs, self.accuracy, self.metadata)
266
+ for i, knotAverage in enumerate(self.greville(nInd)):
267
+ dep[i] = knotAverage
268
+ return type(self)(self.nInd, self.nInd + self.nDep, self.order, self.nCoef, self.knots, coefs, self.metadata)
263
269
 
264
270
  def greville(self, ind = 0):
265
271
  if ind < 0 or ind >= self.nInd: raise ValueError("Invalid independent variable")
266
272
  myKnots = self.knots[ind]
267
- knotAvgs = 0
273
+ knotAverages = 0
268
274
  for ix in range(1, self.order[ind]):
269
- knotAvgs = knotAvgs + myKnots[ix : ix + self.nCoef[ind]]
270
- return knotAvgs / (self.order[ind] - 1)
275
+ knotAverages = knotAverages + myKnots[ix : ix + self.nCoef[ind]]
276
+ return knotAverages / (self.order[ind] - 1)
271
277
 
272
278
  def integrate(self, with_respect_to = 0):
273
279
  if not(0 <= with_respect_to < self.nInd): raise ValueError("Invalid with_respect_to")
@@ -295,7 +301,7 @@ def integrate(self, with_respect_to = 0):
295
301
  for i in range(1, nCoef[with_respect_to]):
296
302
  newCoefs[i] = newCoefs[i - 1] + ((iKnots[degree + i] - iKnots[i]) / degree) * oldCoefs[i - 1]
297
303
 
298
- return type(self)(self.nInd, self.nDep, order, nCoef, knots, newCoefs.swapaxes(0, with_respect_to + 1), self.accuracy, self.metadata)
304
+ return type(self)(self.nInd, self.nDep, order, nCoef, knots, newCoefs.swapaxes(0, with_respect_to + 1), self.metadata)
299
305
 
300
306
  def multiplyAndConvolve(self, other, indMap = None, productType = 'S'):
301
307
  if not(productType == 'C' or productType == 'D' or productType == 'S'): raise ValueError("productType must be 'C', 'D' or 'S'")
@@ -631,7 +637,7 @@ def multiplyAndConvolve(self, other, indMap = None, productType = 'S'):
631
637
  # Now move combined independent variable back to its original axis.
632
638
  coefs = np.moveaxis(newCoefs[:nCoef[ind1]], 0, ind1 + 1)
633
639
 
634
- return type(self)(nInd, nDep, order, nCoef, knots, coefs, self.accuracy + other.accuracy, self.metadata)
640
+ return type(self)(nInd, nDep, order, nCoef, knots, coefs, self.metadata)
635
641
 
636
642
  # Return a matrix of booleans whose [i,j] value indicates if self's partial wrt variable i depends on variable j.
637
643
  def _cross_correlation_matrix(self):
@@ -653,23 +659,20 @@ def _cross_correlation_matrix(self):
653
659
  if not match:
654
660
  break
655
661
  ccm[i, j] = ccm[j, i] = not match
656
-
657
662
  ccm[-1, -1] = True
658
663
  return ccm
659
664
 
660
665
  def normal_spline(self, indices=None):
661
- if abs(self.nInd - self.nDep) != 1: raise ValueError("The number of independent variables must be one different than the number of dependent variables.")
666
+ if abs(self.nInd - self.nDep) != 1: raise ValueError("The number of independent variables must be one less than the number of dependent variables.")
662
667
 
663
668
  # Construct order and knots for generalized cross product of the tangent space.
664
669
  newOrder = []
665
670
  newKnots = []
666
- startUvw = []
667
- endUvw = []
668
- deltaUvw = []
671
+ uvwValues = []
672
+ nCoefs = []
669
673
  totalCoefs = [1]
670
- rank = min(self.nInd, self.nDep)
671
674
  ccm = _cross_correlation_matrix(self)
672
- for i, order, knots in zip(range(self.nInd), self.order, self.knots):
675
+ for i, (order, knots) in enumerate(zip(self.order, self.knots)):
673
676
  # First, calculate the order of the normal for this independent variable.
674
677
  # Note that the total order will be one less than usual, because one of
675
678
  # the tangents is the derivative with respect to that independent variable.
@@ -700,56 +703,67 @@ def normal_spline(self, indices=None):
700
703
  # using that calculation to span uvw from the starting knot to the end for each variable.
701
704
  nCoef = len(newKnots[-1]) - newOrder[-1]
702
705
  totalCoefs.append(totalCoefs[-1] * nCoef)
703
- startUvw.append(uniqueKnots[0])
704
- endUvw.append(uniqueKnots[-1])
705
- deltaUvw.append((uniqueKnots[-1] - uniqueKnots[0]) / (nCoef - 1))
706
-
706
+ uvwValues.append(bspy.Spline(1, 0, [newOrd], [nCoef], [newKnots[-1]], []).greville())
707
+ nCoefs.append(nCoef)
707
708
  points = []
708
- uvw = [*startUvw]
709
+ ijk = [0 for order in self.order]
709
710
  for i in range(totalCoefs[-1]):
710
- points.append((*uvw, *self.normal(uvw, False, indices)))
711
- for j, nCoef, start, end, delta in zip(range(self.nInd), totalCoefs[:-1], startUvw, endUvw, deltaUvw):
711
+ uvw = [uvwValues[j][k] for j, k in enumerate(ijk)]
712
+ points.append(self.normal(uvw, False, indices))
713
+ for j, nCoef in enumerate(totalCoefs[:-1]):
712
714
  if (i + 1) % nCoef == 0:
713
- uvw[j] = min(uvw[j] + delta, end)
715
+ ijk[j] += 1
714
716
  if j > 0:
715
- uvw[j - 1] = previousStart
716
- previousStart = start
717
-
717
+ ijk[j - 1] = 0
718
+ points = np.array(points).T
718
719
  nDep = max(self.nInd, self.nDep) if indices is None else len(indices)
719
- return bspy.Spline.least_squares(self.nInd, nDep, newOrder, points, newKnots, 0, self.metadata)
720
+ nCoefs.reverse()
721
+ points = np.reshape(points, [nDep] + nCoefs)
722
+ points = np.transpose(points, [0] + list(range(self.nInd, 0, -1)))
723
+ return bspy.Spline.least_squares(uvwValues, points, order = newOrder, knots = newKnots, metadata = self.metadata)
724
+ # return bspy.Spline.least_squares(self.nInd, nDep, newOrder, points, newKnots, 0, self.metadata)
725
+
726
+ def rotate(self, vector, angle):
727
+ vector = np.atleast_1d(vector)
728
+ vector = vector / np.linalg.norm(vector)
729
+ if len(vector) != 3: raise ValueError("Rotation vector must have 3 components")
730
+ if self.nDep != 3: raise ValueError("Spline must have exactly 3 dependent variables")
731
+ radians = np.pi * angle / 180.0
732
+ cost = np.cos(radians)
733
+ sint = np.sin(radians)
734
+ kMat = np.array([[0.0, -vector[2], vector[1]],
735
+ [vector[2], 0.0, -vector[0]],
736
+ [-vector[1], vector[0], 0.0]])
737
+ rotMat = np.identity(3) + sint * kMat + (1.0 - cost) * kMat @ kMat
738
+ return list(rotMat) @ self
720
739
 
721
740
  def scale(self, multiplier):
722
741
  if isinstance(multiplier, bspy.Spline):
723
742
  return self.multiply(multiplier, [(ix, ix) for ix in range(min(self.nInd, multiplier.nInd))], 'S')
724
743
  else:
725
744
  if np.isscalar(multiplier):
726
- accuracy = abs(multiplier) * self.accuracy
727
745
  nDep = self.nDep
728
746
  coefs = multiplier * self.coefs
729
747
  elif len(multiplier) == self.nDep:
730
- accuracy = np.linalg.norm(multiplier) * self.accuracy
731
748
  nDep = self.nDep
732
749
  coefs = np.array(self.coefs)
733
750
  for i in range(nDep):
734
751
  coefs[i] *= multiplier[i]
735
752
  elif self.nDep == 1:
736
- accuracy = np.linalg.norm(multiplier) * self.accuracy
737
753
  nDep = len(multiplier)
738
754
  coefs = np.empty((nDep, *self.coefs.shape[1:]), self.coefs.dtype)
739
755
  for i in range(nDep):
740
756
  coefs[i] = multiplier[i] * self.coefs[0]
741
757
  else:
742
758
  raise ValueError("Invalid multiplier")
743
- return type(self)(self.nInd, nDep, self.order, self.nCoef, self.knots, coefs, accuracy, self.metadata)
759
+ return type(self)(self.nInd, nDep, self.order, self.nCoef, self.knots, coefs, self.metadata)
744
760
 
745
- def transform(self, matrix, maxSingularValue=None):
761
+ def transform(self, matrix):
746
762
  if not(matrix.ndim == 2 and matrix.shape[1] == self.nDep): raise ValueError("Invalid matrix")
747
763
 
748
- if maxSingularValue is None:
749
- maxSingularValue = np.linalg.svd(matrix, compute_uv=False)[0]
750
764
  swapped = np.swapaxes(self.coefs, 0, -2)
751
765
  newCoefs = np.swapaxes(matrix @ swapped, 0, -2)
752
- return type(self)(self.nInd, matrix.shape[0], self.order, self.nCoef, self.knots, newCoefs, maxSingularValue * self.accuracy, self.metadata)
766
+ return type(self)(self.nInd, matrix.shape[0], self.order, self.nCoef, self.knots, newCoefs, self.metadata)
753
767
 
754
768
  def translate(self, translationVector):
755
769
  translationVector = np.atleast_1d(translationVector)
@@ -758,4 +772,4 @@ def translate(self, translationVector):
758
772
  coefs = np.array(self.coefs)
759
773
  for i in range(self.nDep):
760
774
  coefs[i] += translationVector[i]
761
- return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, coefs, self.accuracy, self.metadata)
775
+ return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, coefs, self.metadata)
bspy/bspyApp.py CHANGED
@@ -82,7 +82,7 @@ class bspyApp(tk.Tk):
82
82
  controls = tk.Frame(self)
83
83
  controls.pack(side=tk.RIGHT, fill=tk.BOTH, expand=tk.YES)
84
84
 
85
- self.frame = SplineOpenGLFrame(controls)
85
+ self.frame = SplineOpenGLFrame(controls, draw_func=self._DrawSplines)
86
86
  self.frame.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES)
87
87
 
88
88
  buttons = tk.Frame(controls)
@@ -98,6 +98,7 @@ class bspyApp(tk.Tk):
98
98
  self.scale.set(0.5)
99
99
 
100
100
  self.splineList = []
101
+ self.splineDrawList = []
101
102
  self.splineRadius = 0.0
102
103
  self.adjust = None
103
104
  self.workQueue = workQueue
@@ -138,32 +139,25 @@ class bspyApp(tk.Tk):
138
139
 
139
140
  def draw(self, spline, name = None):
140
141
  """Add a `Spline` to the listbox and draw it. Can be called before the app is running."""
141
- spline = DrawableSpline.make_drawable(spline)
142
- if name is not None:
143
- spline.metadata["Name"] = name
144
- self.splineList.append(spline)
145
- self.listBox.insert(tk.END, spline)
142
+ self.list(spline, name)
146
143
  self.listBox.selection_set(self.listBox.size() - 1)
147
144
  self.update()
148
145
 
149
146
  def save_splines(self):
150
- if self.frame.splineDrawList:
151
- initialName = self.frame.splineDrawList[0].metadata.get("Name", "spline") + ".json"
147
+ if self.splineDrawList:
148
+ initialName = self.splineDrawList[0].metadata.get("Name", "spline") + ".json"
152
149
  fileName = filedialog.asksaveasfilename(title="Save splines", initialfile=initialName,
153
150
  defaultextension=".json", filetypes=(('Json files', '*.json'),('All files', '*.*')))
154
151
  if fileName:
155
- self.frame.splineDrawList[0].save(fileName, *self.frame.splineDrawList[1:])
152
+ self.splineDrawList[0].save(fileName, *self.splineDrawList[1:])
156
153
 
157
154
  def load_splines(self):
158
155
  fileName = filedialog.askopenfilename(title="Load splines",
159
156
  defaultextension=".json", filetypes=(('Json files', '*.json'),('All files', '*.*')))
160
157
  if fileName:
161
158
  splines = DrawableSpline.load(fileName)
162
- if isinstance(splines, Spline):
163
- self.list(splines)
164
- else:
165
- for spline in splines:
166
- self.list(spline)
159
+ for spline in splines:
160
+ self.list(spline)
167
161
 
168
162
  def erase_all(self):
169
163
  """Stop drawing all splines. Splines remain in the listbox."""
@@ -203,7 +197,7 @@ class bspyApp(tk.Tk):
203
197
 
204
198
  def update(self):
205
199
  """Update the spline draw list, set the default view, reset the bounds, and refresh the frame."""
206
- self.frame.splineDrawList = []
200
+ self.splineDrawList = []
207
201
  gotOne = False
208
202
  for item in self.listBox.curselection():
209
203
  spline = self.splineList[item]
@@ -215,25 +209,24 @@ class bspyApp(tk.Tk):
215
209
  splineMin = spline.coefs[:3].min(axis=coefsAxis)
216
210
  splineMax = spline.coefs[:3].max(axis=coefsAxis)
217
211
  gotOne = True
218
- self.frame.splineDrawList.append(spline)
212
+ self.splineDrawList.append(spline)
219
213
 
220
214
  if gotOne:
221
215
  newRadius = 0.5 * np.max(splineMax - splineMin)
222
- if not np.isclose(newRadius, self.splineRadius):
223
- self.splineRadius = newRadius
224
- atDefaultEye = np.allclose(self.frame.eye, self.frame.defaultEye)
225
- center = 0.5 * (splineMax + splineMin)
226
- self.frame.SetDefaultView(center + (0.0, 0.0, 3.0 * newRadius), center, (0.0, 1.0, 0.0))
227
- self.frame.ResetBounds()
228
- if atDefaultEye:
229
- self.frame.ResetView()
216
+ self.splineRadius = newRadius
217
+ atDefaultEye = np.allclose(self.frame.eye, self.frame.defaultEye)
218
+ center = 0.5 * (splineMax + splineMin)
219
+ self.frame.SetDefaultView(center + (0.0, 0.0, 3.0 * newRadius), center, (0.0, 1.0, 0.0))
220
+ self.frame.ResetBounds()
221
+ if atDefaultEye:
222
+ self.frame.ResetView()
230
223
  else:
231
224
  self.splineRadius = 0.0
232
225
 
233
226
  if self.adjust is not None:
234
- if self.frame.splineDrawList:
235
- self.bits.set(self.frame.splineDrawList[0].get_options())
236
- animate = self.frame.splineDrawList[0].get_animate()
227
+ if self.splineDrawList:
228
+ self.bits.set(self.splineDrawList[0].get_options())
229
+ animate = self.splineDrawList[0].get_animate()
237
230
  else:
238
231
  self.bits.set(0)
239
232
  animate = None
@@ -243,6 +236,10 @@ class bspyApp(tk.Tk):
243
236
 
244
237
  self.frame.Update()
245
238
 
239
+ def _DrawSplines(self, frame, transform):
240
+ for spline in self.splineDrawList:
241
+ spline._Draw(frame, transform)
242
+
246
243
  def _ListSelectionChanged(self, event):
247
244
  """Handle when the listbox selection has changed."""
248
245
  self.update()
@@ -262,8 +259,8 @@ class bspyApp(tk.Tk):
262
259
  self.checkButtons.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.YES)
263
260
 
264
261
  self.bits = tk.IntVar()
265
- if self.frame.splineDrawList:
266
- self.bits.set(self.frame.splineDrawList[0].get_options())
262
+ if self.splineDrawList:
263
+ self.bits.set(self.splineDrawList[0].get_options())
267
264
  else:
268
265
  self.bits.set(0)
269
266
  _BitCheckbutton(self.checkButtons, DrawableSpline.SHADED, text="Shaded", anchor=tk.W, variable=self.bits, command=self._ChangeOptions).pack(side=tk.TOP, fill=tk.X)
@@ -277,8 +274,8 @@ class bspyApp(tk.Tk):
277
274
  tk.Button(buttons, text='Line color', command=self._LineColorChange).pack(side=tk.TOP, fill=tk.X)
278
275
  self.animate = tk.StringVar()
279
276
  self.animateOptions = {"Animate: Off" : None, "Animate: u(0)" : 0, "Animate: v(1)" : 1, "Animate: w(2)" : 2}
280
- if self.frame.splineDrawList:
281
- animate = self.frame.splineDrawList[0].get_animate()
277
+ if self.splineDrawList:
278
+ animate = self.splineDrawList[0].get_animate()
282
279
  else:
283
280
  animate = None
284
281
  self.animate.set(next(key for key, value in self.animateOptions.items() if value == animate))
@@ -302,7 +299,7 @@ class bspyApp(tk.Tk):
302
299
 
303
300
  def _ChangeOptions(self, options):
304
301
  """Handle when the spline options are changed."""
305
- for spline in self.frame.splineDrawList:
302
+ for spline in self.splineDrawList:
306
303
  spline.set_options(options)
307
304
  self.frame.Update()
308
305
 
@@ -310,7 +307,7 @@ class bspyApp(tk.Tk):
310
307
  """Handle when the spline animation is changed."""
311
308
  nInd = self.animateOptions[value]
312
309
  animating = False
313
- for spline in self.frame.splineDrawList:
310
+ for spline in self.splineDrawList:
314
311
  if nInd is None or nInd < spline.nInd:
315
312
  spline.set_animate(nInd)
316
313
  animating = True
@@ -319,21 +316,21 @@ class bspyApp(tk.Tk):
319
316
 
320
317
  def _FillColorChange(self):
321
318
  """Handle when the fill color changed."""
322
- if self.frame.splineDrawList:
323
- oldColor = 255.0 * self.frame.splineDrawList[0].get_fill_color()
319
+ if self.splineDrawList:
320
+ oldColor = 255.0 * self.splineDrawList[0].get_fill_color()
324
321
  newColor = askcolor(title="Set spline fill color", color="#%02x%02x%02x" % (int(oldColor[0]), int(oldColor[1]), int(oldColor[2])))
325
322
  if newColor[0] is not None:
326
- for spline in self.frame.splineDrawList:
323
+ for spline in self.splineDrawList:
327
324
  spline.set_fill_color(newColor[0])
328
325
  self.frame.Update()
329
326
 
330
327
  def _LineColorChange(self):
331
328
  """Handle when the line color changed."""
332
- if self.frame.splineDrawList:
333
- oldColor = 255.0 * self.frame.splineDrawList[0].get_line_color()
329
+ if self.splineDrawList:
330
+ oldColor = 255.0 * self.splineDrawList[0].get_line_color()
334
331
  newColor = askcolor(title="Set spline line color", color="#%02x%02x%02x" % (int(oldColor[0]), int(oldColor[1]), int(oldColor[2])))
335
332
  if newColor[0] is not None:
336
- for spline in self.frame.splineDrawList:
333
+ for spline in self.splineDrawList:
337
334
  spline.set_line_color(newColor[0])
338
335
  self.frame.Update()
339
336
 
bspy/drawableSpline.py CHANGED
@@ -91,11 +91,6 @@ class DrawableSpline(Spline):
91
91
  coefs : array-like
92
92
  A list of the B-spline coefficients of the spline.
93
93
 
94
- accuracy : `float`
95
- Each spline function is presumed to be an approximation of something else.
96
- The `accuracy` stores the infinity norm error of the difference between
97
- the given spline function and that something else.
98
-
99
94
  metadata : `dict`
100
95
  A dictionary of ancillary data to store with the spline
101
96
 
@@ -135,7 +130,6 @@ class DrawableSpline(Spline):
135
130
  self.nCoef = spline.nCoef
136
131
  self.knots = spline.knots
137
132
  self.coefs = spline.coefs
138
- self.accuracy = spline.accuracy
139
133
  self.metadata = spline.metadata
140
134
  else:
141
135
  Spline.__init__(self, *args, **kwargs)
@@ -151,10 +145,14 @@ class DrawableSpline(Spline):
151
145
  floatCount += 2 + self.order[i] + self.nCoef[i]
152
146
  coefficientCount *= self.nCoef[i]
153
147
  if not(floatCount + self.nDep * coefficientCount <= self._maxFloats): raise ValueError("Spline to large to draw")
154
- self.metadata["fillColor"] = np.array((0.0, 1.0, 0.0, 1.0), np.float32)
155
- self.metadata["lineColor"] = np.array((0.0, 0.0, 0.0, 1.0) if self.nInd > 1 else (1.0, 1.0, 1.0, 1.0), np.float32)
156
- self.metadata["options"] = self.SHADED | self.BOUNDARY
157
- self.metadata["animate"] = None
148
+ if not "fillColor" in self.metadata:
149
+ self.metadata["fillColor"] = np.array((0.0, 1.0, 0.0, 1.0), np.float32)
150
+ if not "lineColor" in self.metadata:
151
+ self.metadata["lineColor"] = np.array((0.0, 0.0, 0.0, 1.0) if self.nInd > 1 else (1.0, 1.0, 1.0, 1.0), np.float32)
152
+ if not "options" in self.metadata:
153
+ self.metadata["options"] = self.SHADED | self.BOUNDARY
154
+ if not "animate" in self.metadata:
155
+ self.metadata["animate"] = None
158
156
 
159
157
  def __str__(self):
160
158
  return self.metadata.get("Name", "[{0}, {1}]".format(self.coefs[0], self.coefs[1]))
@@ -204,7 +202,7 @@ class DrawableSpline(Spline):
204
202
  if rangeCoef > 1.0e-8:
205
203
  coefs[i] = (coefs[i] - minCoef) / rangeCoef
206
204
  else:
207
- coefs[i] = 1.0
205
+ coefs[i] = max(0.0, min(1.0, minCoef))
208
206
  elif spline.nInd == 3:
209
207
  if spline.nDep == 1:
210
208
  spline = spline.graph()
@@ -221,11 +219,11 @@ class DrawableSpline(Spline):
221
219
  if rangeCoef > 1.0e-8:
222
220
  coefs[i] = (coefs[i] - minCoef) / rangeCoef
223
221
  else:
224
- coefs[i] = 1.0
222
+ coefs[i] = max(0.0, min(1.0, minCoef))
225
223
  else:
226
224
  raise ValueError("Can't convert to drawable spline.")
227
225
 
228
- drawable = DrawableSpline(spline.nInd, nDep, spline.order, spline.nCoef, knotList, coefs, spline.accuracy)
226
+ drawable = DrawableSpline(spline.nInd, nDep, spline.order, spline.nCoef, knotList, coefs)
229
227
  drawable.metadata = spline.metadata # Make the original spline share its metadata with its drawable spline
230
228
  if not "fillColor" in drawable.metadata:
231
229
  drawable.metadata["fillColor"] = np.array((0.0, 1.0, 0.0, 1.0), np.float32)