void Geolocation::makeSuccessCallbacks() { ASSERT(lastPosition()); ASSERT(isAllowed()); GeoNotifierVector oneShotsCopy; copyToVector(m_oneShots, oneShotsCopy); GeoNotifierVector watchersCopy; m_watchers.getNotifiersVector(watchersCopy); // Clear the lists before we make the callbacks, to avoid clearing notifiers // added by calls to Geolocation methods from the callbacks, and to prevent // further callbacks to these notifiers. m_oneShots.clear(); // Also clear the set of notifiers waiting for a cached position. All the // oneshots and watchers will receive a position now, and if they happen to // be lingering in that set, avoid this bug: http://crbug.com/311876 . m_requestsAwaitingCachedPosition.clear(); sendPosition(oneShotsCopy, lastPosition()); sendPosition(watchersCopy, lastPosition()); if (!hasListeners()) stopUpdating(); }
/*! Returns an iterator pointing to the last document element inside the frame. \sa begin() */ QTextFrame::iterator QTextFrame::end() const { const QTextDocumentPrivate *priv = docHandle(); int b = priv->blockMap().findNode(firstPosition()); int e = priv->blockMap().findNode(lastPosition()+1); return iterator(const_cast<QTextFrame *>(this), e, b, e); }
void ProxyObject::setParent(const ProxyObjectPtr &parent, TemporalValue<Location>::Time timeStamp, const Location &absLocation, const Location &relLocation) { if (!parent) { unsetParent(timeStamp, absLocation); return; } ProxyObjectPtr oldParent (getParentProxy()); if (oldParent) { oldParent->ProxyObjectProvider::removeListener(this); } parent->ProxyObjectProvider::addListener(this); // Using now() should best allow a linear extrapolation to work. Location lastPosition(globalLocation(timeStamp)); mParentId = parent->getObjectReference(); Location newparentLastGlobal(parent->globalLocation(timeStamp)); /* std::cout<<" Last parent global "<<std::endl<<newparentLastGlobal<<std::endl<< "global loc = "<<std::endl<<lastPosition<< std::endl<<"local loc = "<<std::endl<<lastPosition.toLocal(newparentLastGlobal)<<std::endl; */ mLocation.resetValue(timeStamp, lastPosition.toLocal(newparentLastGlobal)); mLocation.updateValue(timeStamp, relLocation); PositionProvider::notify(&PositionListener::setParent, parent, timeStamp, absLocation, relLocation); }
void Geolocation::setIsAllowed(bool allowed) { // Protect the Geolocation object from garbage collection during a callback. RefPtr<Geolocation> protect(this); // This may be due to either a new position from the service, or a cached // position. m_allowGeolocation = allowed ? Yes : No; // Permission request was made during the startRequest process if (!m_pendingForPermissionNotifiers.isEmpty()) { handlePendingPermissionNotifiers(); m_pendingForPermissionNotifiers.clear(); return; } if (!isAllowed()) { RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); error->setIsFatal(true); handleError(error.get()); m_requestsAwaitingCachedPosition.clear(); return; } // If the service has a last position, use it to call back for all requests. // If any of the requests are waiting for permission for a cached position, // the position from the service will be at least as fresh. if (lastPosition()) makeSuccessCallbacks(); else makeCachedPositionCallbacks(); }
/*! Returns a frame iterator pointing to the end of the table's cell. \sa begin() */ QTextFrame::iterator QTextTableCell::end() const { QTextDocumentPrivate *p = table->docHandle(); int b = p->blockMap().findNode(firstPosition()); int e = p->blockMap().findNode(lastPosition()+1); return QTextFrame::iterator(const_cast<QTextTable *>(table), e, b, e); }
void Geolocation::makeCachedPositionCallbacks() { // All modifications to m_requestsAwaitingCachedPosition are done // asynchronously, so we don't need to worry about it being modified from // the callbacks. for (auto& notifier : m_requestsAwaitingCachedPosition) { // FIXME: This seems wrong, since makeCachedPositionCallbacks() is called in a branch where // lastPosition() is known to be null in Geolocation::setIsAllowed(). notifier->runSuccessCallback(lastPosition()); // If this is a one-shot request, stop it. Otherwise, if the watch still // exists, start the service to get updates. if (!m_oneShots.remove(notifier.get()) && m_watchers.contains(notifier.get())) { if (notifier->hasZeroTimeout() || startUpdating(notifier.get())) notifier->startTimerIfNeeded(); else notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage)); } } m_requestsAwaitingCachedPosition.clear(); if (!hasListeners()) stopUpdating(); }
void Geolocation::makeCachedPositionCallbacks() { // All modifications to m_requestsAwaitingCachedPosition are done // asynchronously, so we don't need to worry about it being modified from // the callbacks. GeoNotifierSet::const_iterator end = m_requestsAwaitingCachedPosition.end(); for (GeoNotifierSet::const_iterator iter = m_requestsAwaitingCachedPosition.begin(); iter != end; ++iter) { GeoNotifier* notifier = iter->get(); notifier->runSuccessCallback(lastPosition()); // If this is a one-shot request, stop it. Otherwise, if the watch still // exists, start the service to get updates. if (m_oneShots.contains(notifier)) m_oneShots.remove(notifier); else if (m_watchers.contains(notifier)) { if (notifier->hasZeroTimeout() || startUpdating(notifier)) notifier->startTimerIfNeeded(); else notifier->setFatalError(PositionError::create(PositionError::POSITION_UNAVAILABLE, failedToStartServiceErrorMessage)); } } m_requestsAwaitingCachedPosition.clear(); if (!hasListeners()) stopUpdating(); }
bool Geolocation::haveSuitableCachedPosition(const PositionOptions& options) { Geoposition* cachedPosition = lastPosition(); if (!cachedPosition) return false; if (!options.maximumAge) return false; DOMTimeStamp currentTimeMillis = convertSecondsToDOMTimeStamp(WallTime::now().secondsSinceEpoch()); return cachedPosition->timestamp() > currentTimeMillis - options.maximumAge; }
void Geolocation::positionChanged() { ASSERT(isAllowed()); m_cachedPosition = lastPosition(); // Stop all currently running timers. stopTimers(); makeSuccessCallbacks(); }
bool Geolocation::haveSuitableCachedPosition(PositionOptions* options) { Geoposition* cachedPosition = lastPosition(); if (!cachedPosition) return false; if (!options->hasMaximumAge()) return true; if (!options->maximumAge()) return false; DOMTimeStamp currentTimeMillis = convertSecondsToDOMTimeStamp(currentTime()); return cachedPosition->timestamp() > currentTimeMillis - options->maximumAge(); }
void Geolocation::makeSuccessCallbacks() { ASSERT(lastPosition()); ASSERT(isAllowed()); GeoNotifierVector oneShotsCopy; copyToVector(m_oneShots, oneShotsCopy); GeoNotifierVector watchersCopy; m_watchers.getNotifiersVector(watchersCopy); // Clear the lists before we make the callbacks, to avoid clearing notifiers // added by calls to Geolocation methods from the callbacks, and to prevent // further callbacks to these notifiers. m_oneShots.clear(); sendPosition(oneShotsCopy, lastPosition()); sendPosition(watchersCopy, lastPosition()); if (!hasListeners()) stopUpdating(); }
bool isNumber(const char *s) { // IMPORTANT: Please reset any member data you declared, as // the same Solution instance will be reused for each test case. trimSpace(s); bool f = lastPosition(s); //trimSpace(s); if(!f || (*s != 'e' && *s != '\0' && *s != ' ')) return false; if(*s == 'e') { //trimSpace(++s); const char *temp = ++s; f = lastPosition(s, true); if(!f || *s == *temp) return false; } while(*s) { if(*s != ' ') return false; s++; } return true; }
void Geolocation::positionChanged() { ASSERT(isAllowed()); // Stop all currently running timers. stopTimers(); if (m_isSuspended) { m_hasChangedPosition = true; return; } RefPtr<Geoposition> position = lastPosition(); ASSERT(position); makeSuccessCallbacks(*position); }
void Geolocation::positionChangedInternal() { m_cachedPosition = lastPosition(); // Stop all currently running timers. stopTimers(); if (!isAllowed()) { // requestPermission() will ask the chrome for permission. This may be // implemented synchronously or asynchronously. In both cases, // makeSuccessCallbacks() will be called if permission is granted, so // there's nothing more to do here. requestPermission(); return; } makeSuccessCallbacks(); }
void ProxyObject::unsetParent(TemporalValue<Location>::Time timeStamp, const Location &absLocation) { ProxyObjectPtr oldParent (getParentProxy()); if (oldParent) { oldParent->ProxyObjectProvider::removeListener(this); } Location lastPosition(globalLocation(timeStamp)); mParentId = SpaceObjectReference::null(); mLocation.resetValue(timeStamp, lastPosition); mLocation.updateValue(timeStamp, absLocation); PositionProvider::notify(&PositionListener::unsetParent, timeStamp, absLocation); }
void Geolocation::setIsAllowed(bool allowed) { // This may be due to either a new position from the service, or a cached // position. m_allowGeolocation = allowed ? Yes : No; #if ENABLE(CLIENT_BASED_GEOLOCATION) if (m_startRequestPermissionNotifier) { if (isAllowed()) { // Permission request was made during the startUpdating process m_startRequestPermissionNotifier->startTimerIfNeeded(); m_startRequestPermissionNotifier = 0; if (!m_frame) return; Page* page = m_frame->page(); if (!page) return; page->geolocationController()->addObserver(this); } else { m_startRequestPermissionNotifier->setFatalError(PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage)); m_oneShots.add(m_startRequestPermissionNotifier); m_startRequestPermissionNotifier = 0; } return; } #endif if (!isAllowed()) { RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); error->setIsFatal(true); handleError(error.get()); m_requestsAwaitingCachedPosition.clear(); return; } // If the service has a last position, use it to call back for all requests. // If any of the requests are waiting for permission for a cached position, // the position from the service will be at least as fresh. if (lastPosition()) makeSuccessCallbacks(); else makeCachedPositionCallbacks(); }
bool Animation::CyclicCoordinateDescent::solve(Math::Vector3f target, float maxAngle) { Math::Vector3f constraint; Math::Vector3f lastPosition(0.0f); Math::Vector3f lastNodePosition(0.0f); do { lastNodePosition[0] = m_lastNode->getGlobalTransformation()(0, 3); lastNodePosition[1] = m_lastNode->getGlobalTransformation()(1, 3); lastNodePosition[2] = m_lastNode->getGlobalTransformation()(2, 3); if ((lastPosition-lastNodePosition).norm() < 0.001f) return false; lastPosition = lastNodePosition; constraint = target - lastNodePosition; ccd(constraint, maxAngle); } while(constraint.norm() > 0.1f); return true; }
void urgDisplay::fillPointMeshTWPRXY(float speed_, float alignYaw_, float alignPitch_, float alignRoll_, bool bCorrectGait) { speed = speed_; alignYaw = alignYaw_; alignPitch = alignPitch_; alignRoll = alignRoll_; pointMesh.clear(); int startIndex = 0; int endIndex = nScans; // starting orientation, location and time ofVec3f lastPosition(0., 0., 0.); float yawZero = fmod(csv.getFloat(startIndex, 1) + 360., 360.); // put in range {0, 360} ofVec3f lastDirection(-1., 0., 0.); // oriention of the IMU is to the left (negative x axis) float timeZero = csv.getFloat(startIndex, 0) / 1000.; float lastTime = timeZero; // add every scan (cross section) to the mesh for (int i = startIndex; i < endIndex; i++) { // get the current location of scan by projecting the last scan direction with a magnitude of the last time interval from the last scan origin float thisTime = csv.getFloat(i, 0) / 1000.; // in seconds float distanceTraveled = (thisTime - lastTime) * speed; ofVec3f changeInPosition = lastDirection.getScaled(distanceTraveled); ofVec3f thisPosition = lastPosition + changeInPosition; // get current orientation of scan with respect to the starting orientation float thisYaw = fmod(csv.getFloat(i, 1) + 720. - yawZero, 360.); ofVec3f thisDirection = ofVec3f(-1., 0., 0.).rotate(-thisYaw, ofVec3f(0., 1., 0.)); // for every point in the scan, rotate it accordingly, then translate it and add it to the mesh for (int j = minIndex + 4; j < maxIndex + 4; j++) { // get the initial (recorded) coordinates float px = csv.getFloat(i, 2 * j); float py = csv.getFloat(i, 2 * j + 1); ofVec3f recordedPosition(px, py, 0.); // cull out coorinates that are too close to the camera // use manhattan distance to speed up processing // double sqDist = recordedPosition.distanceSquared(ofVec3f(0.,0.,0.)); // if (sqDist < minSqDist2Cam) continue; // first rotate so it's perpendicular to thisDirection (align virtual lidar scanner to coorindate system of razor IMU) ofVec3f alignedPosition = recordedPosition; alignedPosition.rotate(-alignRoll, 0., 0.); // first roll (rotate right) alignedPosition.rotate(0., 0., -alignPitch); // then pitch (pull back) alignedPosition.rotate(0., -alignYaw, 0.); // finally yaw (turn clockwise) ofVec3f orientedPosition = alignedPosition; // optionally, correct for gait here (recorded pitch and roll) if (bCorrectGait) { float thisRoll = csv.getFloat(i, 3); orientedPosition.rotate(-thisRoll, 0., 0.); float thisPitch = csv.getFloat(i, 2); orientedPosition.rotate(0., 0., -thisPitch); } // orient position to thisDirection orientedPosition.rotate(0., -thisYaw, 0.); // move point to actual location ofVec3f translatedPosition = orientedPosition + thisPosition; // add translated position to the mesh pointMesh.addVertex(translatedPosition); pointMesh.addColor(ofFloatColor(1., 1., 1.)); } lastTime = thisTime; lastDirection = thisDirection; lastPosition = thisPosition; } }
/*! Returns the last valid cursor position in this cell. \sa firstCursorPosition() */ QTextCursor QTextTableCell::lastCursorPosition() const { return QTextCursor(table->d_func()->pieceTable, lastPosition()); }
/*! Returns the last cursor position inside the frame. \sa firstCursorPosition() firstPosition() lastPosition() */ QTextCursor QTextFrame::lastCursorPosition() const { Q_D(const QTextFrame); return QTextCursor(d->pieceTable, lastPosition()); }
void OnCreated( wxObject* wxobject, wxWindow* /*wxparent*/ ) { // For storing objects whose postion needs to be determined std::vector< std::pair< wxObject*, wxGBSizerItem* > > newObjects; wxGBPosition lastPosition( 0, 0 ); // Get sizer wxGridBagSizer* sizer = wxDynamicCast( wxobject, wxGridBagSizer ); if ( NULL == sizer ) { wxLogError( wxT("This should be a wxGridBagSizer!") ); return; } // Add the children IManager* manager = GetManager(); size_t count = manager->GetChildCount( wxobject ); if ( 0 == count ) { // wxGridBagSizer gets upset sometimes without children sizer->Add( 0, 0, wxGBPosition( 0, 0 ) ); return; } for ( size_t i = 0; i < count; ++i ) { // Should be a GBSizerItem wxObject* wxsizerItem = manager->GetChild( wxobject, i ); IObject* isizerItem = manager->GetIObject( wxsizerItem ); // Get the location of the item wxGBSpan span( isizerItem->GetPropertyAsInteger( _("rowspan") ), isizerItem->GetPropertyAsInteger( _("colspan") ) ); int column = isizerItem->GetPropertyAsInteger( _("column") ); if ( column < 0 ) { // Needs to be auto positioned after the other children are added wxGBSizerItem* item = GetGBSizerItem( isizerItem, lastPosition, span, manager->GetChild( wxsizerItem, 0 ) ); if ( item != NULL ) { newObjects.push_back( std::pair< wxObject*, wxGBSizerItem* >( wxsizerItem, item ) ); } continue; } wxGBPosition position( isizerItem->GetPropertyAsInteger( _("row") ), column ); // Check for intersection if ( sizer->CheckForIntersection( position, span ) ) { continue; } lastPosition = position; // Add the child to the sizer wxGBSizerItem* item = GetGBSizerItem( isizerItem, position, span, manager->GetChild( wxsizerItem, 0 ) ); if ( item != NULL ) { sizer->Add( item ); } } std::vector< std::pair< wxObject*, wxGBSizerItem* > >::iterator it; for ( it = newObjects.begin(); it != newObjects.end(); ++it ) { wxGBPosition position = it->second->GetPos(); wxGBSpan span = it->second->GetSpan(); int column = position.GetCol(); while ( sizer->CheckForIntersection( position, span ) ) { column++; position.SetCol( column ); } it->second->SetPos( position ); sizer->Add( it->second ); GetManager()->ModifyProperty( it->first, _("row"), wxString::Format( wxT("%i"), position.GetRow() ), false ); GetManager()->ModifyProperty( it->first, _("column"), wxString::Format( wxT("%i"), column ), false ); } }
esvg::render::PointList esvg::render::Path::generateListPoints(int32_t _level, int32_t _recurtionMax, float _threshold) { ESVG_VERBOSE(spacingDist(_level) << "Generate List Points ... from a path"); esvg::render::PointList out; std::vector<esvg::render::Point> tmpListPoint; vec2 lastPosition(0.0f, 0.0f); vec2 lastAngle(0.0f, 0.0f); int32_t lastPointId = -1; bool PathStart = false; // Foreach element, we move in the path: for(auto &it : m_listElement) { if (it == nullptr) { continue; } ESVG_VERBOSE(spacingDist(_level+1) << " Draw : " << *it); switch (it->getType()) { case esvg::render::path_stop: if (tmpListPoint.size() != 0) { if (tmpListPoint.size() == 0) { ESVG_WARNING(spacingDist(_level+1) << " Request path stop of not starting path ..."); } else { tmpListPoint.back().setEndPath(); out.addList(tmpListPoint); tmpListPoint.clear(); } } lastAngle = vec2(0.0f, 0.0f); // nothing alse to do ... break; case esvg::render::path_close: if (tmpListPoint.size() != 0) { if (tmpListPoint.size() == 0) { ESVG_WARNING(spacingDist(_level+1) << " Request path close of not starting path ..."); } else { // find the previous tart of the path ... tmpListPoint.front().m_type = esvg::render::Point::type::join; // Remove the last point if it is the same position... vec2 delta = (tmpListPoint.front().m_pos - tmpListPoint.back().m_pos).absolute(); if ( delta.x() <= 0.00001 && delta.y() <= 0.00001) { tmpListPoint.pop_back(); ESVG_VERBOSE(" Remove point Z property : " << tmpListPoint.back().m_pos << " with delta=" << delta); } out.addList(tmpListPoint); tmpListPoint.clear(); } } lastAngle = vec2(0.0f, 0.0f); // nothing alse to do ... break; case esvg::render::path_moveTo: // stop last path if (tmpListPoint.size() != 0) { tmpListPoint.back().setEndPath(); out.addList(tmpListPoint); tmpListPoint.clear(); } // create a new one if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } lastPosition += it->getPos(); tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::start)); lastAngle = lastPosition; break; case esvg::render::path_lineTo: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::start)); } if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } lastPosition += it->getPos(); tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); lastAngle = lastPosition; break; case esvg::render::path_lineToH: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::start)); } if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } lastPosition += it->getPos(); tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); lastAngle = lastPosition; break; case esvg::render::path_lineToV: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::start)); } if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } lastPosition += it->getPos(); tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); lastAngle = lastPosition; break; case esvg::render::path_curveTo: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); } { vec2 lastPosStore(lastPosition); if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } vec2 pos1 = lastPosition + it->getPos1(); vec2 pos2 = lastPosition + it->getPos2(); vec2 pos = lastPosition + it->getPos(); interpolateCubicBezier(tmpListPoint, _recurtionMax, _threshold, lastPosStore, pos1, pos2, pos, 0, esvg::render::Point::type::join); lastPosition = pos; lastAngle = pos2; } break; case esvg::render::path_smoothCurveTo: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); } { vec2 lastPosStore(lastPosition); if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } vec2 pos2 = lastPosition + it->getPos2(); vec2 pos = lastPosition + it->getPos(); // generate Pos 1 vec2 pos1 = lastPosStore*2.0f - lastAngle; interpolateCubicBezier(tmpListPoint, _recurtionMax, _threshold, lastPosStore, pos1, pos2, pos, 0, esvg::render::Point::type::join); lastPosition = pos; lastAngle = pos2; } break; case esvg::render::path_bezierCurveTo: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); } { vec2 lastPosStore(lastPosition); if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } vec2 pos = lastPosition + it->getPos(); vec2 tmp1 = lastPosition + it->getPos1(); // generate pos1 and pos2 vec2 pos1 = lastPosStore + (tmp1 - lastPosStore)*0.666666666f; vec2 pos2 = pos + (tmp1 - pos)*0.666666666f; interpolateCubicBezier(tmpListPoint, _recurtionMax, _threshold, lastPosStore, pos1, pos2, pos, 0, esvg::render::Point::type::join); lastPosition = pos; lastAngle = tmp1; } break; case esvg::render::path_bezierSmoothCurveTo: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); } { vec2 lastPosStore(lastPosition); if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } vec2 pos = lastPosition + it->getPos(); vec2 tmp1 = lastPosStore*2.0f - lastAngle; // generate pos1 and pos2 vec2 pos1 = lastPosStore + (tmp1 - lastPosStore)*0.666666666f; vec2 pos2 = pos + (tmp1 - pos)*0.66666666f; interpolateCubicBezier(tmpListPoint, _recurtionMax, _threshold, lastPosStore, pos1, pos2, pos, 0, esvg::render::Point::type::join); lastPosition = pos; lastAngle = tmp1; } break; case esvg::render::path_elliptic: // If no previous point, we need to create the last point has start ... if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); } { ememory::SharedPtr<esvg::render::ElementElliptic> tmpIt(ememory::dynamicPointerCast<esvg::render::ElementElliptic>(it)); float angle = tmpIt->m_angle * (M_PI / 180.0); ESVG_TODO(spacingDist(_level+1) << " Elliptic arc: radius=" << tmpIt->getPos1()); ESVG_TODO(spacingDist(_level+1) << " angle=" << tmpIt->m_angle); ESVG_TODO(spacingDist(_level+1) << " m_largeArcFlag=" << tmpIt->m_largeArcFlag); ESVG_TODO(spacingDist(_level+1) << " m_sweepFlag=" << tmpIt->m_sweepFlag); vec2 lastPosStore(lastPosition); if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } vec2 pos = lastPosition + it->getPos(); float rotationX = tmpIt->m_angle * (M_PI / 180.0); vec2 radius = tmpIt->getPos1(); #ifdef DEBUG m_debugInformation.addSegment(lastPosStore, pos); #endif vec2 delta = lastPosStore - pos; float ddd = delta.length(); if ( ddd < 1e-6f || radius.x() < 1e-6f || radius.y() < 1e-6f) { ESVG_WARNING("Degenerate arc in Line"); if (tmpListPoint.size() == 0) { tmpListPoint.push_back(esvg::render::Point(lastPosition, esvg::render::Point::type::join)); } tmpListPoint.push_back(esvg::render::Point(pos, esvg::render::Point::type::join)); } else { // Convert to center point parameterization. // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes // procedure describe here : http://www.w3.org/TR/SVG11/implnote.html#ArcConversionCenterToEndpoint // Compute delta' mat2 matrixRotationCenter = etk::mat2Rotate(-rotationX); vec2 deltaPrim = matrixRotationCenter * (delta*0.5f); ddd = (deltaPrim.x()*deltaPrim.x())/(radius.x()*radius.x()) + (deltaPrim.y()*deltaPrim.y())/(radius.y()*radius.y()); if (ddd > 1.0f) { #ifndef __STDCPP_LLVM__ ddd = std::sqrt(ddd); #else ddd = sqrtf(ddd); #endif radius *= ddd; } // Compute center' float sss = 0.0f; float ssa = radius.x()*radius.x()*radius.y()*radius.y() - radius.x()*radius.x()*deltaPrim.y()*deltaPrim.y() - radius.y()*radius.y()*deltaPrim.x()*deltaPrim.x(); float ssb = radius.x()*radius.x()*deltaPrim.y()*deltaPrim.y() + radius.y()*radius.y()*deltaPrim.x()*deltaPrim.x(); if (ssa < 0.0f) { ssa = 0.0f; } if (ssb > 0.0f) { #ifndef __STDCPP_LLVM__ sss = std::sqrt(ssa / ssb); #else sss = sqrtf(ssa / ssb); #endif } if (tmpIt->m_largeArcFlag == tmpIt->m_sweepFlag) { sss *= -1.0f; } vec2 centerPrime(sss * radius.x() * deltaPrim.y() / radius.y(), sss * -radius.y() * deltaPrim.x() / radius.x()); // Compute center from center' mat2 matrix = etk::mat2Rotate(rotationX); vec2 center = (lastPosStore + pos)*0.5f + matrix*centerPrime; #ifdef DEBUG m_debugInformation.addSegment(center-vec2(3.0,3.0), center+vec2(3.0,3.0)); m_debugInformation.addSegment(center-vec2(3.0,-3.0), center+vec2(3.0,-3.0)); #endif // Calculate theta1, and delta theta. vec2 vectorA = (deltaPrim - centerPrime) / radius; vec2 vectorB = (deltaPrim + centerPrime) / radius * -1.0f; #ifdef DEBUG m_debugInformation.addSegment(center, center+vectorA*radius.x()); m_debugInformation.addSegment(center, center+vectorB*radius.y()); #endif // Initial angle float theta1 = vectorAngle(vec2(1.0f,0.0f), vectorA); // Delta angle float deltaTheta = vectorAngle(vectorA, vectorB); // special case of invert angle... if ( ( deltaTheta == float(M_PI) || deltaTheta == -float(M_PI)) && tmpIt->m_sweepFlag == false) { deltaTheta *= -1.0f; } if (tmpIt->m_largeArcFlag == true) { // Choose large arc if (deltaTheta > 0.0f) { deltaTheta -= 2.0f*M_PI; } else { deltaTheta += 2.0f*M_PI; } } // Approximate the arc using cubic spline segments. matrix.translate(center); // Split arc into max 90 degree segments. // The loop assumes an iteration per end point (including start and end), this +1. #ifndef __STDCPP_LLVM__ int32_t ndivs = int32_t(std::abs(deltaTheta) / (M_PI*0.5f)) + 1; #else int32_t ndivs = int32_t(fabs(deltaTheta) / (M_PI*0.5f)) + 1; #endif float hda = (deltaTheta / float(ndivs)) * 0.5f; #ifndef __STDCPP_LLVM__ float kappa = std::abs(4.0f / 3.0f * (1.0f - std::cos(hda)) / std::sin(hda)); #else float kappa = fabs(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); #endif if (deltaTheta < 0.0f) { kappa = -kappa; } vec2 pointPosPrevious(0.0,0.0); vec2 tangentPrevious(0.0,0.0); for (int32_t iii=0; iii<=ndivs; ++iii) { float a = theta1 + deltaTheta * (float(iii)/(float)ndivs); #ifndef __STDCPP_LLVM__ delta = vec2(std::cos(a), std::sin(a)); #else delta = vec2(cosf(a), sinf(a)); #endif // position vec2 pointPos = matrix * vec2(delta.x()*radius.x(), delta.y()*radius.y()); // tangent vec2 tangent = matrix.applyScaleRotation(vec2(-delta.y()*radius.x() * kappa, delta.x()*radius.y() * kappa)); if (iii > 0) { vec2 zlastPosStore(lastPosition); if (it->getRelative() == false) { lastPosition = vec2(0.0f, 0.0f); } vec2 zpos1 = pointPosPrevious + tangentPrevious; vec2 zpos2 = pointPos - tangent; vec2 zpos = pointPos; interpolateCubicBezier(tmpListPoint, _recurtionMax, _threshold, zlastPosStore, zpos1, zpos2, zpos, 0, esvg::render::Point::type::join); lastPosition = zpos; lastAngle = zpos2; } pointPosPrevious = pointPos; tangentPrevious = tangent; } } lastPosition = pos; } break; default: ESVG_ERROR(spacingDist(_level+1) << " Unknow PATH commant (internal error)"); break; } } // special case : No request end of path ==> open path: if (tmpListPoint.size() != 0) { ESVG_VERBOSE("Auto-end PATH"); tmpListPoint.back().setEndPath(); out.addList(tmpListPoint); tmpListPoint.clear(); } out.display(); return out; }