Dali 3D User Interface Engine
path-impl.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 // CLASS HEADER
20 
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 
24 // INTERNAL INCLUDES
28 
29 namespace Dali
30 {
31 
32 namespace Internal
33 {
34 
35 namespace
36 {
37 
38 // Properties
39 
40 // Name Type writable animatable constraint-input enum for index-checking
42 DALI_PROPERTY( "points", ARRAY, true, false, false, Dali::Path::Property::POINTS )
43 DALI_PROPERTY( "controlPoints", ARRAY, true, false, false, Dali::Path::Property::CONTROL_POINTS )
45 
46 
58 const float BezierBasisCoeff[] = { -1.0f, 3.0f, -3.0f, 1.0f,
59  3.0f, -6.0f, 3.0f, 0.0f,
60  -3.0f, 3.0f, 0.0f, 0.0f,
61  1.0f, 0.0f, 0.0f, 0.0f };
62 
64 
66 {
67  return Dali::Path::New();
68 }
69 
71 
72 inline bool PathIsComplete(const Dali::Vector<Vector3>& point, const Dali::Vector<Vector3>& controlPoint)
73 {
74  return ( point.Size() > 1 && controlPoint.Size() == (point.Size()-1)*2 );
75 }
76 
77 } //Unnamed namespace
78 
80 {
81  return new Path();
82 }
83 
85 : Object()
86 {
87 }
88 
90 {
91 }
92 
93 Path* Path::Clone(const Path& path)
94 {
95  Path* clone = new Path();
96  clone->SetPoints( path.GetPoints() );
97  clone->SetControlPoints( path.GetControlPoints() );
98 
99  return clone;
100 }
101 
102 unsigned int Path::GetDefaultPropertyCount() const
103 {
104  return DEFAULT_PROPERTY_COUNT;
105 }
106 
108 {
109  indices.Reserve( DEFAULT_PROPERTY_COUNT );
110 
111  for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
112  {
113  indices.PushBack( i );
114  }
115 }
116 
118 {
119  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
120  {
121  return DEFAULT_PROPERTY_DETAILS[index].name;
122  }
123 
124  // index out of range
125  return NULL;
126 }
127 
128 Property::Index Path::GetDefaultPropertyIndex(const std::string& name) const
129 {
131 
132  // Look for name in default properties
133  for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
134  {
135  const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
136  if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
137  {
138  index = i;
139  break;
140  }
141  }
142  return index;
143 }
144 
146 {
147  if( index < DEFAULT_PROPERTY_COUNT )
148  {
149  return DEFAULT_PROPERTY_DETAILS[index].type;
150  }
151 
152  // index out of range
153  return Property::NONE;
154 }
155 
157 {
158  if( index == Dali::Path::Property::POINTS )
159  {
161  Property::Array* array = value.GetArray();
162  Property::Array::SizeType pointCount = mPoint.Count();
163 
164  if( array )
165  {
166  array->Reserve( pointCount );
167  for( Property::Array::SizeType i = 0; i < pointCount; ++i )
168  {
169  array->PushBack( mPoint[i] );
170  }
171  }
172  return value;
173  }
174  else if( index == Dali::Path::Property::CONTROL_POINTS )
175  {
177  Property::Array* array = value.GetArray();
178  Property::Array::SizeType controlpointCount = mControlPoint.Count();
179 
180  if( array )
181  {
182  array->Reserve( controlpointCount );
183  for( Property::Array::SizeType i = 0; i < controlpointCount; ++i )
184  {
185  array->PushBack( mControlPoint[i] );
186  }
187  }
188  return value;
189  }
190 
191  return Property::Value();
192 }
193 
195 {
196  const Property::Array* array = propertyValue.GetArray();
197  if( array )
198  {
199  Property::Array::SizeType propertyArrayCount = array->Count();
200  if( index == Dali::Path::Property::POINTS )
201  {
202  mPoint.Reserve( propertyArrayCount );
203  for( Property::Array::SizeType i = 0; i < propertyArrayCount; ++i )
204  {
205  Vector3 point;
206  array->GetElementAt( i ).Get( point );
207  mPoint.PushBack( point );
208  }
209  }
210  else if( index == Dali::Path::Property::CONTROL_POINTS )
211  {
212  mControlPoint.Reserve( propertyArrayCount );
213  for( Property::Array::SizeType i = 0; i < propertyArrayCount; ++i )
214  {
215  Vector3 point;
216  array->GetElementAt( i ).Get( point );
217  mControlPoint.PushBack( point );
218  }
219  }
220  }
221 }
222 
224 {
225  if( index < DEFAULT_PROPERTY_COUNT )
226  {
227  return DEFAULT_PROPERTY_DETAILS[index].writable;
228  }
229 
230  return false;
231 }
232 
234 {
235  if( index < DEFAULT_PROPERTY_COUNT )
236  {
237  return DEFAULT_PROPERTY_DETAILS[index].animatable;
238  }
239 
240  return false;
241 }
242 
244 {
245  if( index < DEFAULT_PROPERTY_COUNT )
246  {
247  return DEFAULT_PROPERTY_DETAILS[index].constraintInput;
248  }
249 
250  return false;
251 }
252 
253 void Path::AddPoint(const Vector3& point )
254 {
255  mPoint.PushBack( point );
256 }
257 
258 void Path::AddControlPoint(const Vector3& point )
259 {
260  mControlPoint.PushBack( point );
261 }
262 
263 unsigned int Path::GetNumberOfSegments() const
264 {
265  return (mPoint.Size()>1)?mPoint.Size()-1:0;
266 }
267 
268 void Path::GenerateControlPoints( float curvature )
269 {
270  unsigned int numSegments = GetNumberOfSegments();
271  DALI_ASSERT_ALWAYS( numSegments > 0 && "Need at least 1 segment to generate control points" ); // need at least 1 segment
272 
273  mControlPoint.Resize( numSegments * 2);
274 
275  //Generate two control points for each segment
276  for( unsigned int i(0); i<numSegments; ++i )
277  {
278  //Segment end-points
279  Vector3 p1 = mPoint[i];
280  Vector3 p2 = mPoint[i+1];
281 
282  Vector3 p0;
283  if( i == 0 )
284  {
285  //There's no previous point. We chose a point in the line defined by the two end points at
286  //a 1/8th of the distance between them.
287  p0 = p1 - (p2 - p1)/8.0f;
288  }
289  else
290  {
291  //Previous point
292  p0 = mPoint[i-1];
293  }
294 
295  Vector3 p3;
296  if( i == numSegments - 1)
297  {
298  //There's no next point. We chose a point in the line defined by the two end points at
299  //a 1/8th of the distance between them.
300  p3 = p2 - (p1 - p2)/8.0f;
301  }
302  else
303  {
304  //Next point
305  p3 = mPoint[i+2];
306  }
307 
308  Vector3 p0p1 = p1 - p0;
309  Vector3 p1p2 = p2 - p1;
310  Vector3 p2p3 = p3 - p2;
311 
312  float length = p1p2.Length();
313 
314  Vector3 tangentOut = ( p0p1*length + p1p2*p0p1.Length() ) * 0.5f;
315  tangentOut.Normalize();
316 
317  Vector3 tangentIn = ( p1p2*p2p3.Length() + p2p3*length ) * 0.5f;
318  tangentIn.Normalize();
319 
320  //Use curvature to scale the tangents
321  length *= curvature;
322  mControlPoint[2*i] = p1 + tangentOut*length;
323  mControlPoint[2*i+1] = p2 - tangentIn*length;
324  }
325 }
326 
327 void Path::FindSegmentAndProgress( float t, unsigned int& segment, float& tLocal ) const
328 {
329  //Find segment and local progress
330  unsigned int numSegs = GetNumberOfSegments();
331 
332  if( t <= 0.0f || numSegs == 0 )
333  {
334  segment = 0;
335  tLocal = 0.0f;
336  }
337  else if( t >= 1.0f )
338  {
339  segment = numSegs-1;
340  tLocal = 1.0f;
341  }
342  else
343  {
344  segment = t * numSegs;
345  float segLength = 1.0f / numSegs;
346  float segStart = (float)segment * segLength;
347  tLocal = (t - segStart) * numSegs;
348  }
349 }
350 
351 void Path::Sample( float t, Vector3& position, Vector3& tangent ) const
352 {
353  if( !SampleAt(t, position, tangent) )
354  {
355  DALI_ASSERT_ALWAYS(!"Spline not fully initialized" );
356  }
357 }
358 
359 bool Path::SampleAt( float t, Vector3& position, Vector3& tangent ) const
360 {
361  bool done = false;
362 
364  {
365  unsigned int segment;
366  float tLocal;
367  FindSegmentAndProgress( t, segment, tLocal );
368 
369  //Get points and control points in the segment
370  const Vector3& controlPoint0 = mControlPoint[2*segment];
371  const Vector3& controlPoint1 = mControlPoint[2*segment+1];
372  const Vector3& point0 = mPoint[segment];
373  const Vector3& point1 = mPoint[segment+1];
374 
375  if(tLocal < Math::MACHINE_EPSILON_1)
376  {
377  position = point0;
378  tangent = ( controlPoint0 - point0 ) * 3.0f;
379  tangent.Normalize();
380  }
381  else if( (1.0 - tLocal) < Math::MACHINE_EPSILON_1)
382  {
383  position = point1;
384  tangent = ( point1 - controlPoint1 ) * 3.0f;
385  tangent.Normalize();
386  }
387  else
388  {
389  const Vector4 sVect(tLocal*tLocal*tLocal, tLocal*tLocal, tLocal, 1.0f );
390  const Vector3 sVectDerivative(3.0f*tLocal*tLocal, 2.0f*tLocal, 1.0f );
391 
392  //X
393  Vector4 cVect( point0.x, controlPoint0.x, controlPoint1.x, point1.x);
394 
395  Vector4 A = BezierBasis * cVect;
396  position.x = sVect.Dot4(A);
397  tangent.x = sVectDerivative.Dot(Vector3(A));
398 
399  //Y
400  cVect.x = point0.y;
401  cVect.y = controlPoint0.y;
402  cVect.z = controlPoint1.y;
403  cVect.w = point1.y;
404 
405  A = BezierBasis * cVect;
406  position.y = sVect.Dot4(A);
407  tangent.y = sVectDerivative.Dot(Vector3(A));
408 
409  //Z
410  cVect.x = point0.z;
411  cVect.y = controlPoint0.z;
412  cVect.z = controlPoint1.z;
413  cVect.w = point1.z;
414 
415  A = BezierBasis * cVect;
416  position.z = sVect.Dot4(A);
417  tangent.z = sVectDerivative.Dot(Vector3(A));
418 
419  tangent.Normalize();
420  }
421 
422  done = true;
423  }
424 
425  return done;
426 }
427 
428 bool Path::SamplePosition( float t, Vector3& position ) const
429 {
430  bool done = false;
431 
433  {
434  unsigned int segment;
435  float tLocal;
436  FindSegmentAndProgress( t, segment, tLocal );
437 
438  const Vector3& controlPoint0 = mControlPoint[2*segment];
439  const Vector3& controlPoint1 = mControlPoint[2*segment+1];
440  const Vector3& point0 = mPoint[segment];
441  const Vector3& point1 = mPoint[segment+1];
442 
443  if(tLocal < Math::MACHINE_EPSILON_1)
444  {
445  position = point0;
446  }
447  else if( (1.0 - tLocal) < Math::MACHINE_EPSILON_1)
448  {
449  position = point1;
450  }
451  else
452  {
453  const Vector4 sVect(tLocal*tLocal*tLocal, tLocal*tLocal, tLocal, 1.0f );
454 
455  //X
456  Vector4 cVect( point0.x, controlPoint0.x, controlPoint1.x, point1.x);
457  position.x = sVect.Dot4(BezierBasis * cVect);
458 
459  //Y
460  cVect.x = point0.y;
461  cVect.y = controlPoint0.y;
462  cVect.z = controlPoint1.y;
463  cVect.w = point1.y;
464  position.y = sVect.Dot4(BezierBasis * cVect);
465 
466  //Z
467  cVect.x = point0.z;
468  cVect.y = controlPoint0.z;
469  cVect.z = controlPoint1.z;
470  cVect.w = point1.z;
471  position.z = sVect.Dot4(BezierBasis * cVect);
472  }
473 
474  done = true;
475  }
476 
477  return done;
478 }
479 
480 bool Path::SampleTangent( float t, Vector3& tangent ) const
481 {
482  bool done = false;
483 
485  {
486  unsigned int segment;
487  float tLocal;
488  FindSegmentAndProgress( t, segment, tLocal );
489 
490  const Vector3& controlPoint0 = mControlPoint[2*segment];
491  const Vector3& controlPoint1 = mControlPoint[2*segment+1];
492  const Vector3& point0 = mPoint[segment];
493  const Vector3& point1 = mPoint[segment+1];
494 
495  if(tLocal < Math::MACHINE_EPSILON_1)
496  {
497  tangent = ( controlPoint0 - point0 ) * 3.0f;
498  }
499  else if( (1.0f - tLocal) < Math::MACHINE_EPSILON_1)
500  {
501  tangent = ( point1 - controlPoint1 ) * 3.0f;
502  }
503  else
504  {
505  const Vector3 sVectDerivative(3.0f*tLocal*tLocal, 2.0f*tLocal, 1.0f );
506 
507  //X
508  Vector4 cVect( point0.x, controlPoint0.x, controlPoint1.x, point1.x);
509  tangent.x = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
510 
511  //Y
512  cVect.x = point0.y;
513  cVect.y = controlPoint0.y;
514  cVect.z = controlPoint1.y;
515  cVect.w = point1.y;
516  tangent.y = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
517 
518  //Z
519  cVect.x = point0.z;
520  cVect.y = controlPoint0.z;
521  cVect.z = controlPoint1.z;
522  cVect.w = point1.z;
523  tangent.z = sVectDerivative.Dot(Vector3(BezierBasis * cVect));
524  }
525 
526  tangent.Normalize();
527  done = true;
528  }
529 
530  return done;
531 }
532 
533 Vector3& Path::GetPoint( size_t index )
534 {
535  DALI_ASSERT_ALWAYS( index < mPoint.Size() && "Path: Point index out of bounds" );
536 
537  return mPoint[index];
538 }
539 
541 {
542  DALI_ASSERT_ALWAYS( index < mControlPoint.Size() && "Path: Control Point index out of bounds" );
543 
544  return mControlPoint[index];
545 }
546 
547 size_t Path::GetPointCount() const
548 {
549  return mPoint.Size();
550 }
551 
553 {
554  mPoint.Clear();
555 }
556 
558 {
559  mControlPoint.Clear();
560 }
561 
562 } // Internal
563 } // Dali
Dali Docs Home
Read more about Dali