Input: Upload a file with a multi upload as a sync request . [CODESPLIT] public void putFileMulti ( File file , final String objectKey , String fileName , String eTag , final long length ) throws QSException { if ( partSize < 4 * 1024 * 1024 ) { throw new QSException ( "Every part of the file can not smaller than 4 MB." ) ; } if ( recorder == null || recorder . get ( objectKey ) == null ) { Bucket . InitiateMultipartUploadInput inputInit = new Bucket . InitiateMultipartUploadInput ( ) ; Bucket . InitiateMultipartUploadOutput initOutput = bucket . initiateMultipartUpload ( objectKey , inputInit ) ; int code = initOutput . getStatueCode ( ) ; // Initiate occurs an error. if ( code < 200 || code >= 300 ) { if ( callBack != null ) { OutputModel outputModel = new OutputModel ( ) ; outputModel . setStatueCode ( code ) ; outputModel . setMessage ( initOutput . getMessage ( ) ) ; callBack . onAPIResponse ( objectKey , outputModel ) ; } return ; } uploadModel = new UploadModel ( ) ; uploadModel . setTotalSize ( length ) ; uploadModel . setUploadID ( initOutput . getUploadID ( ) ) ; } else { byte [ ] bytes = recorder . get ( objectKey ) ; String json = new String ( bytes ) ; uploadModel = new Gson ( ) . fromJson ( json , UploadModel . class ) ; // Check status of the task. if ( uploadModel . isUploadComplete ( ) ) { if ( callBack != null ) { OutputModel outputModel = new OutputModel ( ) ; outputModel . setStatueCode ( 201 ) ; outputModel . setMessage ( "This task has been uploaded." ) ; callBack . onAPIResponse ( objectKey , outputModel ) ; } return ; } } uploadModel . setTotalSize ( length ) ; // Check if all parts have been completely uploaded. if ( uploadModel . isFileComplete ( ) ) { completeMultiUpload ( objectKey , fileName , eTag , uploadModel . getUploadID ( ) , length ) ; } else { for ( int i = uploadModel . getCurrentPart ( ) ; i < partCounts ; i ++ ) { // Make records when a new part starts to upload. uploadModel . setCurrentPart ( i ) ; uploadModel . setBytesWritten ( i * partSize ) ; setData ( objectKey , recorder ) ; // Request cancelled. Stop upload other parts. if ( cancellationHandler != null && cancellationHandler . isCancelled ( ) ) { // Keep parts data into the upload. setData ( objectKey , recorder ) ; break ; } long contentLength = Math . min ( partSize , ( file . length ( ) - uploadModel . getCurrentPart ( ) * partSize ) ) ; Bucket . UploadMultipartInput input = new Bucket . UploadMultipartInput ( ) ; input . setBodyInputFilePart ( file ) ; input . setFileOffset ( i * partSize ) ; input . setContentLength ( contentLength ) ; input . setPartNumber ( i ) ; input . setUploadID ( uploadModel . getUploadID ( ) ) ; // Create request to upload a part. RequestHandler requestHandler = bucket . uploadMultipartRequest ( objectKey , input ) ; // Progress listener if ( progressListener != null ) { requestHandler . setProgressListener ( new BodyProgressListener ( ) { @ Override public void onProgress ( long len , long size ) { long bytesWritten = uploadModel . getCurrentPart ( ) * partSize + len ; progressListener . onProgress ( objectKey , bytesWritten , length ) ; } } ) ; } // Cancellation handler. requestHandler . setCancellationHandler ( cancellationHandler ) ; // Sign with server if needed. sign ( requestHandler ) ; // Send the request. OutputModel send = requestHandler . send ( ) ; // Check response. if ( send . getStatueCode ( ) != 200 && send . getStatueCode ( ) != 201 ) { // Failed. setData ( objectKey , recorder ) ; // On upload failed if ( callBack != null ) callBack . onAPIResponse ( objectKey , send ) ; // Once failed, break the circle. break ; } else if ( i == partCounts - 1 ) { // Success and it is the last part of th file. // Make a record in the upload. uploadModel . setBytesWritten ( length ) ; uploadModel . setFileComplete ( true ) ; setData ( objectKey , recorder ) ; } } // Finally check. if ( uploadModel . isFileComplete ( ) ) { completeMultiUpload ( objectKey , fileName , eTag , uploadModel . getUploadID ( ) , length ) ; } } }


Input: When sending a request will call this method to sign with server . [CODESPLIT] private void sign ( RequestHandler requestHandler ) throws QSException { if ( callBack != null ) { String signed = callBack . onSignature ( requestHandler . getStringToSignature ( ) ) ; if ( ! QSStringUtil . isEmpty ( signed ) ) requestHandler . setSignature ( callBack . onAccessKey ( ) , signed ) ; String correctTime = callBack . onCorrectTime ( requestHandler . getStringToSignature ( ) ) ; if ( correctTime != null && correctTime . trim ( ) . length ( ) > 0 ) requestHandler . getBuilder ( ) . setHeader ( QSConstant . HEADER_PARAM_KEY_DATE , correctTime ) ; } }


Input: Set data in the upload with a recorder . [CODESPLIT] private void setData ( String objectKey , Recorder recorder ) { if ( recorder == null ) return ; String upload = new Gson ( ) . toJson ( uploadModel ) ; recorder . set ( objectKey , upload . getBytes ( ) ) ; }


Input: Complete the multi upload . [CODESPLIT] private void completeMultiUpload ( String objectKey , String fileName , String eTag , String uploadID , long length ) throws QSException { CompleteMultipartUploadInput completeMultipartUploadInput = new CompleteMultipartUploadInput ( uploadID , partCounts , 0 ) ; completeMultipartUploadInput . setContentLength ( length ) ; // Set content disposition to the object. if ( ! QSStringUtil . isEmpty ( fileName ) ) { try { String keyName = QSStringUtil . percentEncode ( fileName , "UTF-8" ) ; completeMultipartUploadInput . setContentDisposition ( String . format ( "attachment; filename=\"%s\"; filename*=utf-8''%s" , keyName , keyName ) ) ; } catch ( UnsupportedEncodingException e ) { e . printStackTrace ( ) ; } } // Set the Md5 info to the object. if ( ! QSStringUtil . isEmpty ( eTag ) ) { completeMultipartUploadInput . setETag ( eTag ) ; } RequestHandler requestHandler = bucket . completeMultipartUploadRequest ( objectKey , completeMultipartUploadInput ) ; sign ( requestHandler ) ; Bucket . CompleteMultipartUploadOutput send = ( Bucket . CompleteMultipartUploadOutput ) requestHandler . send ( ) ; if ( send . getStatueCode ( ) == 200 || send . getStatueCode ( ) == 201 ) { uploadModel . setUploadComplete ( true ) ; setData ( objectKey , recorder ) ; } // Response callback. if ( callBack != null ) callBack . onAPIResponse ( objectKey , send ) ; }


Input: Upload a file with a simple put object upload as a sync request . <br > If a file s size is less than { [CODESPLIT] public void putFile ( File file , final String objectKey , String fileName , long length ) throws QSException { PutObjectInput input = new PutObjectInput ( ) ; input . setContentLength ( length ) ; input . setBodyInputFile ( file ) ; // Set content disposition to the object. if ( ! QSStringUtil . isEmpty ( fileName ) ) { try { String keyName = QSStringUtil . percentEncode ( fileName , "UTF-8" ) ; input . setContentDisposition ( String . format ( "attachment; filename=\"%s\"; filename*=utf-8''%s" , keyName , keyName ) ) ; } catch ( UnsupportedEncodingException e ) { e . printStackTrace ( ) ; } } RequestHandler requestHandler = bucket . putObjectRequest ( objectKey , input ) ; // Set progress listener. if ( progressListener != null ) { requestHandler . setProgressListener ( new BodyProgressListener ( ) { @ Override public void onProgress ( long len , long size ) { progressListener . onProgress ( objectKey , len , size ) ; } } ) ; } // Cancellation handler. requestHandler . setCancellationHandler ( cancellationHandler ) ; // Sign if needed. sign ( requestHandler ) ; OutputModel outputModel = requestHandler . send ( ) ; if ( callBack != null ) callBack . onAPIResponse ( objectKey , outputModel ) ; }


Input: Invoking a FavoriteAction toggles it . [CODESPLIT] @ Override public void invoke ( final ActionRequest req , final ActionResponse res ) throws IOException { final NotificationEntry entry = getTarget ( ) ; final String notificationId = entry . getId ( ) ; final Set < String > favoriteNotices = this . getFavoriteNotices ( req ) ; if ( favoriteNotices . contains ( notificationId ) ) { favoriteNotices . remove ( notificationId ) ; } else { favoriteNotices . add ( notificationId ) ; } setFavoriteNotices ( req , favoriteNotices ) ; }


Input: / * package - private [CODESPLIT] Set < String > getFavoriteNotices ( final PortletRequest req ) { final HashSet < String > rslt = new HashSet < String > ( ) ; final PortletPreferences prefs = req . getPreferences ( ) ; final String [ ] ids = prefs . getValues ( FAVORITE_NOTIFICATION_IDS_PREFERENCE , new String [ 0 ] ) ; for ( int i = 0 ; i < ids . length ; i ++ ) { rslt . add ( ids [ i ] ) ; } return rslt ; }


Input: / * package - private [CODESPLIT] void setFavoriteNotices ( final PortletRequest req , final Set < String > favoriteNotices ) { final String [ ] ids = favoriteNotices . toArray ( new String [ favoriteNotices . size ( ) ] ) ; final PortletPreferences prefs = req . getPreferences ( ) ; try { prefs . setValues ( FAVORITE_NOTIFICATION_IDS_PREFERENCE , ids ) ; prefs . store ( ) ; } catch ( Exception e ) { throw new RuntimeException ( e ) ; } }


Input: / * Implementation [CODESPLIT] private static Comparator < NotificationEntry > chooseConfiguredComparator ( HttpServletRequest req ) { final String strategyName = req . getParameter ( SORT_STRATEGY_PARAMETER_NAME ) ; if ( strategyName == null ) { // No strategy means "natural" ordering;  we won't be sorting... return null ; } // We WILL be sorting;  work out the details... try { final SortStrategy strategy = SortStrategy . valueOf ( strategyName . toUpperCase ( ) ) ; // tolerant of case mismatch final String orderName = req . getParameter ( SORT_ORDER_PARAMETER_NAME ) ; final SortOrder order = StringUtils . isNotBlank ( orderName ) ? SortOrder . valueOf ( orderName . toUpperCase ( ) ) // tolerant of case mismatch : SortOrder . valueOf ( SORT_ORDER_DEFAULT ) ; return order . equals ( SortOrder . ASCENDING ) ? strategy . getComparator ( ) // Default/ascending order : Collections . reverseOrder ( strategy . getComparator ( ) ) ; // Descending order } catch ( IllegalArgumentException e ) { LOGGER . warn ( "Unable to sort based on parameters {}='{}' and {}='{}'" , SORT_STRATEGY_PARAMETER_NAME , strategyName , SORT_ORDER_PARAMETER_NAME , req . getParameter ( SORT_ORDER_PARAMETER_NAME ) ) ; } // We didn't succeed in selecting a strategy & order return null ; }


Input: Caller must insure that the state being set has not already been added to the entry to avoid multiple events with the same state . [CODESPLIT] public void addEntryState ( PortletRequest req , String entryId , NotificationState state ) { if ( usernameFinder . isAuthenticated ( req ) ) { final String username = usernameFinder . findUsername ( req ) ; String idStr = entryId . replaceAll ( ID_PREFIX , "" ) ; // remove the prefix JpaEntry jpaEntry = notificationDao . getEntry ( Long . parseLong ( idStr ) ) ; if ( jpaEntry != null ) { JpaEvent event = new JpaEvent ( ) ; event . setEntry ( jpaEntry ) ; event . setState ( state ) ; event . setTimestamp ( new Timestamp ( new Date ( ) . getTime ( ) ) ) ; event . setUsername ( username ) ; notificationDao . createOrUpdateEvent ( event ) ; } else { throw new IllegalArgumentException ( "JpaEntry not found" ) ; } } }


Input: / * Implementation [CODESPLIT] private NotificationResponse prepareResponse ( Set < JpaEntry > entries , String username ) { Map < String , NotificationCategory > categories = new HashMap <> ( ) ; for ( JpaEntry entry : entries ) { // Choose a category title final String categryTitle = ! StringUtils . isBlank ( entry . getCategory ( ) ) ? entry . getCategory ( ) : messages . getMessage ( UNCATEGORIZED_MESSAGE_CODE , null , UNCATEGORIZED_DEFAULT_MESSAGE , Locale . getDefault ( ) ) ; // Obtain the category object matching the title NotificationCategory category = categories . get ( categryTitle ) ; if ( category == null ) { category = new NotificationCategory ( ) ; category . setTitle ( categryTitle ) ; categories . put ( categryTitle , category ) ; } // Prepare a NotificationEntry NotificationEntry y = prepareEntry ( entry , username ) ; if ( y != null ) { category . addEntries ( Collections . singletonList ( y ) ) ; } } // Create & load the response final List < NotificationCategory > cList = new ArrayList <> ( categories . values ( ) ) ; final List < NotificationError > eList = Collections . emptyList ( ) ; // Anything here? return new NotificationResponse ( cList , eList ) ; }


Input:
Creates a { @link NotificationEntry } from a { @link JpaEntry } but will return null if that process cannot be performed in a valid way . [CODESPLIT] private NotificationEntry prepareEntry ( JpaEntry entry , String username ) { /*
         * Implementation Note:  Most notification fields are optional.  This
         * method impl avoids setting fields within the NotificationEntry when
         * those fields are (essentially) unspecified on the JpaEntry in order
         * not to run afoul of any logic (present or future) that may trigger
         * when a field is set (e.g. validation, virtual members, change
         * tracking).
         */ NotificationEntry rslt = new NotificationEntry ( ) ; // Id & title will always be present rslt . setId ( ID_PREFIX + entry . getId ( ) ) ; final String title = entry . getTitle ( ) ; if ( StringUtils . isBlank ( title ) ) { log . warn ( "User '" + username + "' had a notification with an empty title:  " + entry . toString ( ) ) ; return null ; } rslt . setTitle ( title ) ; // But these fields are optional if ( ! StringUtils . isBlank ( entry . getBody ( ) ) ) { // Body rslt . setBody ( entry . getBody ( ) ) ; } if ( entry . getDueDate ( ) != null ) { // Due date rslt . setDueDate ( entry . getDueDate ( ) ) ; } if ( ! StringUtils . isBlank ( entry . getImage ( ) ) ) { // Image rslt . setImage ( entry . getImage ( ) ) ; } if ( ! StringUtils . isBlank ( entry . getLinkText ( ) ) ) { // Link text rslt . setLinkText ( entry . getLinkText ( ) ) ; } if ( entry . getPriority ( ) != 0 ) { // Priority rslt . setPriority ( entry . getPriority ( ) ) ; } if ( ! StringUtils . isBlank ( entry . getSource ( ) ) ) { // Source rslt . setSource ( entry . getSource ( ) ) ; } if ( ! StringUtils . isBlank ( entry . getUrl ( ) ) ) { // Url rslt . setUrl ( entry . getUrl ( ) ) ; } // States (transaction log) Map < NotificationState , Date > states = prepareStates ( entry , username ) ; rslt . setStates ( states ) ; // Collections of items... if ( ! entry . getAttributes ( ) . isEmpty ( ) ) { // Attributes List < NotificationAttribute > attributes = prepareAttributes ( entry . getAttributes ( ) ) ; rslt . setAttributes ( attributes ) ; } if ( ! entry . getActions ( ) . isEmpty ( ) ) { // Actions List < NotificationAction > actions = prepareActions ( entry . getActions ( ) , username ) ; rslt . setAvailableActions ( actions ) ; } return rslt ; }


Input: Helper method to determine if an SSPToken has expired . [CODESPLIT] public boolean hasExpired ( ) { long now = System . currentTimeMillis ( ) ; if ( created + ( expiresIn * 1000 ) + TIMEOUT_BUFFER > now ) { return false ; } return true ; }


Input: Is the { [CODESPLIT] public boolean contains ( NotificationEntry entry ) { return StringUtils . isNotBlank ( entry . getId ( ) ) && entry . getId ( ) . startsWith ( JpaNotificationService . ID_PREFIX ) ; }


Input:
Provides the known history of status changes for the specified user and notification <strong > in chronological order< / strong > . [CODESPLIT] @ Override public List < EventDTO > getHistory ( NotificationEntry entry , String username ) { List < EventDTO > rslt = Collections . emptyList ( ) ; // default /*
         * The JPA system owns status tracking, but it only tracks status for
         * entries that it owns.  If the entry is not already a JPA-backed
         * entry, we would use a JPA-side "proxy."
         */ final EntryDTO entryDto = contains ( entry ) ? jpaNotificationRestService . getNotification ( entry , false ) : fetchJpaProxyIfAvailable ( entry ) ; // There can't be history if there isn't (yet) a proxy if ( entryDto != null ) { rslt = jpaNotificationRestService . getEventsByNotificationAndUser ( entryDto . getId ( ) , username ) ; } return rslt ; }


Input: / * Implementation [CODESPLIT] private EntryDTO fetchJpaProxyIfAvailable ( NotificationEntry entry ) { EntryDTO rslt = null ; // default final List < EntryDTO > list = jpaNotificationRestService . getNotificationsBySourceAndCustomAttribute ( PROXY_SOURCE_NAME , PROXY_ID_ATTRIBUTE , entry . getId ( ) ) ; logger . debug ( "Search for JPA-backed entry with id='{}' returned the following:  {}" , entry . getId ( ) , list ) ; switch ( list . size ( ) ) { case 1 : // Cool;  we have one... rslt = list . get ( 0 ) ; break ; case 0 : // Also cool;  we don't have one... break ; default : // Not cool... throw new IllegalStateException ( "More than one JPA-back entry exists for id=" + entry . getId ( ) ) ; } return rslt ; }


Input: Add all entries from the notification category to the <code > allEntries< / code > list after adding an attribute category that contains the category . That allows UIs that want the convenience of an uncategorized list such as dataTables to obtain the data in a simple format that requires no additional processing but maintains the knowledge of the category of the entries . [CODESPLIT] private void addAndCategorizeEntries ( List < NotificationEntry > allEntries , NotificationCategory notificationCategory ) { for ( NotificationEntry entry : notificationCategory . getEntries ( ) ) { List < NotificationAttribute > attrs = new ArrayList <> ( entry . getAttributes ( ) ) ; attrs . add ( new NotificationAttribute ( "category" , notificationCategory . getTitle ( ) ) ) ; entry . setAttributes ( attrs ) ; allEntries . add ( entry ) ; } }


Input: Get the list of notifications . Supports optional ( and recommended! ) paging [CODESPLIT] @ RequestMapping ( method = RequestMethod . GET ) @ ResponseBody public List < EntryDTO > getNotifications ( @ RequestParam ( value = "page" , required = false ) Integer page , @ RequestParam ( value = "pageSize" , required = false ) Integer pageSize ) { return restService . getNotifications ( page , pageSize ) ; }


Input: Create a notification . [CODESPLIT] @ RequestMapping ( method = RequestMethod . POST ) @ ResponseStatus ( HttpStatus . CREATED ) @ ResponseBody public EntryDTO createNotification ( HttpServletRequest req , HttpServletResponse response , @ RequestBody EntryDTO entry ) { EntryDTO persisted = restService . createNotification ( entry ) ; String url = getSingleNotificationRESTUrl ( req , persisted . getId ( ) ) ; response . addHeader ( "Location" , url ) ; return persisted ; }


Input: Get 1 notification by id . [CODESPLIT] @ RequestMapping ( value = "/{notificationId}" , method = RequestMethod . GET ) @ ResponseBody public EntryDTO getNotification ( HttpServletResponse response , @ PathVariable ( "notificationId" ) long id , @ RequestParam ( value = "full" , required = false , defaultValue = "false" ) boolean full ) { EntryDTO notification = restService . getNotification ( id , full ) ; if ( notification == null ) { response . setStatus ( HttpStatus . NOT_FOUND . value ( ) ) ; return null ; } return notification ; }


Input: Get the set of addressees for a notification . [CODESPLIT] @ RequestMapping ( value = "/{notificationId}/addressees" , method = RequestMethod . GET ) @ ResponseBody public Set < AddresseeDTO > getAddressees ( @ PathVariable ( "notificationId" ) long id ) { return restService . getAddressees ( id ) ; }


Input: Create a new addressee for a notification . [CODESPLIT] @ RequestMapping ( value = "/{notificationId}/addressees" , method = RequestMethod . POST ) @ ResponseBody @ ResponseStatus ( HttpStatus . CREATED ) public AddresseeDTO addAddressee ( HttpServletRequest req , HttpServletResponse resp , @ PathVariable ( "notificationId" ) long id , @ RequestBody AddresseeDTO addressee ) { AddresseeDTO dto = restService . createAddressee ( id , addressee ) ; if ( dto == null ) { resp . setStatus ( HttpStatus . NOT_FOUND . value ( ) ) ; return null ; } String url = getSingleNotificationRESTUrl ( req , id ) + "/addressee/" + dto . getId ( ) ; resp . addHeader ( "Location" , url ) ; return dto ; }


Input: Get a specific addressee [CODESPLIT] @ RequestMapping ( value = "/{notificationId}/addressees/{addresseeId}" , method = RequestMethod . GET ) @ ResponseBody public AddresseeDTO getAddressee ( HttpServletResponse resp , @ PathVariable ( "notificationId" ) long notificationId , @ PathVariable ( "addresseeId" ) long addresseeId ) { AddresseeDTO dto = restService . getAddressee ( addresseeId ) ; if ( dto == null ) { resp . setStatus ( HttpStatus . NOT_FOUND . value ( ) ) ; return null ; } return dto ; }


Input: Get the list of events for a notification . [CODESPLIT] @ RequestMapping ( value = "/{notificationId}/events" , method = RequestMethod . GET ) @ ResponseBody public List < EventDTO > getEventsByNotification ( @ PathVariable ( "notificationId" ) long id ) { return restService . getEventsByNotification ( id ) ; }


Input: Get a specific event . [CODESPLIT] @ RequestMapping ( value = "/{notificationId}/events/{eventId}" , method = RequestMethod . GET ) @ ResponseBody public EventDTO getEvent ( HttpServletResponse response , @ PathVariable ( "notificationId" ) long notificationId , @ PathVariable ( "eventId" ) long eventId ) { EventDTO event = restService . getEvent ( eventId ) ; if ( event == null ) { response . setStatus ( HttpStatus . NOT_FOUND . value ( ) ) ; return null ; } return event ; }


Input: Create a new event . [CODESPLIT] @ RequestMapping ( value = "/{notificationId}/events" , method = RequestMethod . POST ) @ ResponseStatus ( HttpStatus . CREATED ) @ ResponseBody public EventDTO createEvent ( HttpServletRequest req , HttpServletResponse resp , @ PathVariable ( "notificationId" ) long notificationId , @ RequestBody EventDTO event ) { EventDTO dto = restService . createEvent ( notificationId , event ) ; if ( dto == null ) { resp . setStatus ( HttpStatus . NOT_FOUND . value ( ) ) ; return null ; } String url = getSingleNotificationRESTUrl ( req , notificationId ) + "/state/" + dto . getId ( ) ; resp . addHeader ( "Location" , url ) ; return dto ; }


Input: Build the URL for a specific notification . [CODESPLIT] private String getSingleNotificationRESTUrl ( HttpServletRequest request , long id ) { String path = request . getContextPath ( ) + REQUEST_ROOT + id ; try { URL url = new URL ( request . getScheme ( ) , request . getServerName ( ) , request . getServerPort ( ) , path ) ; return url . toExternalForm ( ) ; } catch ( MalformedURLException e ) { // if it fails, just return a relative path.  Not ideal, but better than nothing... log . warn ( "Error building Location header" , e ) ; return path ; } }


Input: Provides a complete transaction log for a notification and a single recipient <strong > in chronological order< / strong > . [CODESPLIT] @ Override @ Transactional ( readOnly = true ) public List < EventDTO > getEventsByNotificationAndUser ( long notificationId , String username ) { final List < JpaEvent > events = notificationDao . getEvents ( notificationId , username ) ; return notificationMapper . toEventList ( events ) ; }


Input: / * Implementation [CODESPLIT] private NotificationResponse doFetch ( List < String > feedUrls , String username ) { final List < NotificationCategory > categories = new ArrayList <> ( ) ; final List < NotificationError > errors = new ArrayList <> ( ) ; for ( String item : feedUrls ) { // It's okay to pull a response from cache, if we have one, since refresh happens in invoke() final Element m = cache . get ( item ) ; if ( m != null ) { // ## CACHE HIT ## if ( logger . isDebugEnabled ( ) ) { logger . debug ( "Feed cache HIT for url:  " + item ) ; } final NotificationCategory category = ( NotificationCategory ) m . getObjectValue ( ) ; categories . add ( category ) ; } else { // ## CACHE MISS ## if ( logger . isDebugEnabled ( ) ) { logger . debug ( "Feed cache MISS for url:  " + item ) ; logger . debug ( "Checking the following feed URL for notifications for user '" + username + "' -- " + item ) ; } final NotificationCategory category = fetchFromSourceUrl ( item ) ; if ( category != null ) { cache . put ( new Element ( item , category ) ) ; categories . add ( category ) ; } else { final NotificationError error = new NotificationError ( ) ; error . setError ( "Service Unavailable" ) ; error . setSource ( getName ( ) ) ; errors . add ( error ) ; } } } final NotificationResponse rslt = new NotificationResponse ( ) ; rslt . setCategories ( categories ) ; rslt . setErrors ( errors ) ; return rslt ; }


Input: Search for a JpaEntry with the specified Id . If the entry exists in the persistence context it is returned ; otherwise null is returned . [CODESPLIT] @ Override @ Transactional ( readOnly = true ) public JpaEntry getEntry ( long entryId ) { Validate . isTrue ( entryId > 0 , "Invalid entryId:  " + entryId ) ; JpaEntry rslt = entityManager . find ( JpaEntry . class , entryId ) ; return rslt ; }


Input:
Obtains information about the user from the Authorization header in the form of an OIDC Id token . In the future it would be better to provide a standard tool ( bean ) for this job in the <code > uPortal - soffit - renderer< / code > component . [CODESPLIT] private Jws < Claims > parseOidcToken ( HttpServletRequest req ) { final String authHeader = req . getHeader ( HttpHeaders . AUTHORIZATION ) ; if ( StringUtils . isBlank ( authHeader ) || ! authHeader . startsWith ( Headers . BEARER_TOKEN_PREFIX ) ) { /*
             * No OIDC token available
             */ return null ; } final String bearerToken = authHeader . substring ( Headers . BEARER_TOKEN_PREFIX . length ( ) ) ; try { // Validate & parse the JWT final Jws < Claims > rslt = Jwts . parser ( ) . setSigningKey ( signatureKey ) . parseClaimsJws ( bearerToken ) ; logger . debug ( "Found the following OIDC Id token:  {}" , rslt . toString ( ) ) ; return rslt ; } catch ( Exception e ) { logger . info ( "The following Bearer token is unusable:  '{}'" , bearerToken ) ; logger . debug ( "Failed to validate and/or parse the specified Bearer token" , e ) ; } return null ; }


Input: Subclasses <em > must< / em > call <code > super . init () < / code > . [CODESPLIT] @ PostConstruct public void init ( ) { super . init ( ) ; // Very important! try { nonEmptyResponse = objectMapper . readValue ( jsonResource . getURL ( ) , NotificationResponse . class ) ; } catch ( IOException ioe ) { final String msg = "Failed to load JSON from resource:  " + jsonResource ; throw new RuntimeException ( msg , ioe ) ; } }


Input: Set the SSP API Context . Note : this method will ensure that that the API context starts with / and ensures that it does not end with a / . [CODESPLIT] @ Value ( "${studentSuccessPlanService.sspContext:/ssp}" ) public void setSspContext ( String sspContext ) { // ensure leading '/' if ( ! sspContext . startsWith ( "/" ) ) { sspContext = "/" + sspContext ; } // remove any trailing '/' if ( sspContext . endsWith ( "/" ) ) { sspContext = sspContext . replaceAll ( "/*$" , "" ) ; } this . sspContext = sspContext ; }


Input: { [CODESPLIT] @ Override public < T > ResponseEntity < T > doRequest ( SSPApiRequest < T > request ) throws MalformedURLException , RestClientException { SSPToken token = getAuthenticationToken ( false ) ; request . setHeader ( AUTHORIZATION , token . getTokenType ( ) + " " + token . getAccessToken ( ) ) ; URL url = getSSPUrl ( request . getUrlFragment ( ) , true ) ; ResponseEntity < T > response = restTemplate . exchange ( url . toExternalForm ( ) , request . getMethod ( ) , request . getRequestEntity ( ) , request . getResponseClass ( ) , request . getUriParameters ( ) ) ; // if we get a 401, the token may have unexpectedly expired (eg. ssp server restart). // Clear it, get a new token and replay the request one time. if ( response . getStatusCode ( ) == HttpStatus . UNAUTHORIZED ) { token = getAuthenticationToken ( true ) ; request . setHeader ( AUTHORIZATION , token . getTokenType ( ) + " " + token . getAccessToken ( ) ) ; return restTemplate . exchange ( url . toExternalForm ( ) , request . getMethod ( ) , request . getRequestEntity ( ) , request . getResponseClass ( ) , request . getUriParameters ( ) ) ; } return response ; }


Input: { [CODESPLIT] public URL getSSPUrl ( String urlFragment , boolean useContext ) throws MalformedURLException { String path = ( useContext ) ? sspContext + urlFragment : urlFragment ; return new URL ( sspProtocol , sspHost , sspPort , path ) ; }


Input: Get the authentication token to use . [CODESPLIT] private synchronized SSPToken getAuthenticationToken ( boolean forceUpdate ) throws MalformedURLException , RestClientException { if ( authenticationToken != null && ! authenticationToken . hasExpired ( ) && ! forceUpdate ) { return authenticationToken ; } String authString = getClientId ( ) + ":" + getClientSecret ( ) ; String authentication = new Base64 ( ) . encodeToString ( authString . getBytes ( ) ) ; HttpHeaders headers = new HttpHeaders ( ) ; headers . add ( AUTHORIZATION , BASIC + " " + authentication ) ; // form encode the grant_type... MultiValueMap < String , String > form = new LinkedMultiValueMap <> ( ) ; form . add ( GRANT_TYPE , CLIENT_CREDENTIALS ) ; HttpEntity < MultiValueMap < String , String > > request = new HttpEntity <> ( form , headers ) ; URL authURL = getAuthenticationURL ( ) ; authenticationToken = restTemplate . postForObject ( authURL . toExternalForm ( ) , request , SSPToken . class ) ; return authenticationToken ; }


Input: Returns the { [CODESPLIT] public NotificationEntry findNotificationEntryById ( final String notificationId ) { // Assertions if ( notificationId == null ) { String msg = "Argument 'notificationId' cannot be null" ; throw new IllegalArgumentException ( msg ) ; } // Providing a brute-force implementation for  // now;  we can improve it if it becomes important. NotificationEntry rslt = null ; // default -- means not present for ( NotificationCategory category : categories ) { for ( NotificationEntry entry : category . getEntries ( ) ) { if ( notificationId . equals ( entry . getId ( ) ) ) { rslt = entry ; break ; } } if ( rslt != null ) { break ; } } return rslt ; }


Input: Combine the contents of this response with the provided response and return a <b > new instance< / b > of { @link NotificationResponse } . The original instances are unchanged . [CODESPLIT] public NotificationResponse combine ( NotificationResponse response ) { NotificationResponse rslt = new NotificationResponse ( this ) ; rslt . addCategories ( response . getCategories ( ) ) ; rslt . addErrors ( response . getErrors ( ) ) ; return rslt ; }


Input: Return a <b > new instance< / b > of { @link NotificationResponse } from which the specified errors have been removed . The original instances are unchanged . [CODESPLIT] public NotificationResponse filterErrors ( Set < Integer > hiddenErrorKeys ) { NotificationResponse rslt = new NotificationResponse ( this ) ; List < NotificationError > filteredErrors = new ArrayList <> ( ) ; for ( NotificationError r : errors ) { if ( ! hiddenErrorKeys . contains ( r . getKey ( ) ) ) { filteredErrors . add ( r ) ; } } rslt . setErrors ( filteredErrors ) ; // deep copy return rslt ; }


Input: Return a <b > new instance< / b > of { [CODESPLIT] public NotificationResponse filter ( Predicate < NotificationEntry > predicate ) { final List < NotificationCategory > filteredCategories = categories . stream ( ) . map ( category -> { final List < NotificationEntry > filteredEntries = category . getEntries ( ) . stream ( ) . filter ( predicate ) . collect ( Collectors . toList ( ) ) ; return filteredEntries . size ( ) > 0 ? new NotificationCategory ( category . getTitle ( ) , filteredEntries ) : null ; } ) . filter ( value -> value != null ) . collect ( Collectors . toList ( ) ) ; return new NotificationResponse ( filteredCategories , getErrors ( ) ) ; // deep copy }


Input: Provides the total number of notifications contained in the response . [CODESPLIT] @ JsonIgnore @ XmlTransient public int size ( ) { return categories . stream ( ) . map ( NotificationCategory :: getEntries ) . mapToInt ( List :: size ) . sum ( ) ; }


Input: Insert the given categories and their entries into the any existing categories of the same title . If a category doesn t match an existing one add it to the list . [CODESPLIT] private void addCategories ( List < NotificationCategory > newCategories ) { if ( newCategories == null ) { return ; } // Start with a deep copy of the method parameter to simplify remaining logic newCategories = newCategories . parallelStream ( ) . map ( NotificationCategory :: cloneNoExceptions ) . collect ( Collectors . toList ( ) ) ; // Create a map of current categories by title for processing Map < String , NotificationCategory > catsByName = this . categories . parallelStream ( ) . collect ( toMap ( c -> c . getTitle ( ) . toLowerCase ( ) , c -> c ) ) ; // Split new categories between those that match an existing category and those that are completely new Map < Boolean , List < NotificationCategory > > matchingNewCats = newCategories . stream ( ) . collect ( partitioningBy ( c -> catsByName . containsKey ( c . getTitle ( ) . toLowerCase ( ) ) ) ) ; // Add new entries to existing categories matchingNewCats . get ( Boolean . TRUE ) . stream ( ) . forEachOrdered ( c -> catsByName . get ( c . getTitle ( ) . toLowerCase ( ) ) . addEntries ( c . getEntries ( ) ) ) ; // Add new categories this . categories . addAll ( matchingNewCats . get ( Boolean . FALSE ) ) ; }


Input: Best guess as to the reason this method exists : beans that produce fresh { [CODESPLIT] public NotificationResponse cloneIfNotCloned ( ) { try { return isCloned ( ) ? this : ( NotificationResponse ) this . clone ( ) ; } catch ( CloneNotSupportedException e ) { log . error ( "Failed to clone() the sourceResponse" , e ) ; } return this ; }


Input: Returns an empty collection and logs the event . All concrete implementations of { [CODESPLIT] @ Override public NotificationResponse fetch ( HttpServletRequest request ) { logger . warn ( "Notification service '{}' was invoked by the portlet-agnostic API, but it " + "doesn't override fetch(HttpServletRequest)" , getName ( ) ) ; return NotificationResponse . EMPTY_RESPONSE ; }


Input: Fetch the set of SSP tasks for the uPortal user . [CODESPLIT] @ Override public NotificationResponse fetch ( PortletRequest req ) { PortletPreferences preferences = req . getPreferences ( ) ; String enabled = preferences . getValue ( SSP_NOTIFICATIONS_ENABLED , "false" ) ; if ( ! "true" . equalsIgnoreCase ( enabled ) ) { return new NotificationResponse ( ) ; } String personId = getPersonId ( req ) ; if ( personId == null ) { // Not all students will have active SSP records, // so if no entry is found in SSP, just return an // empty response set. return new NotificationResponse ( ) ; } String urlFragment = getActiveTaskUrl ( ) ; SSPApiRequest < String > request = new SSPApiRequest <> ( urlFragment , String . class ) . addUriParameter ( "personId" , personId ) ; ResponseEntity < String > response ; try { response = sspApi . doRequest ( request ) ; } catch ( Exception e ) { log . error ( "Error reading SSP Notifications: " + e . getMessage ( ) ) ; return notificationError ( e . getMessage ( ) ) ; } if ( response . getStatusCode ( ) . series ( ) != HttpStatus . Series . SUCCESSFUL ) { log . error ( "Error reading SSP Notifications: " + response ) ; return notificationError ( response . getBody ( ) ) ; } NotificationResponse notification = mapToNotificationResponse ( req , response ) ; return notification ; }


Input: Error handler . [CODESPLIT] private NotificationResponse notificationError ( String errorMsg ) { NotificationError error = new NotificationError ( ) ; error . setError ( errorMsg ) ; error . setSource ( getClass ( ) . getSimpleName ( ) ) ; NotificationResponse notification = new NotificationResponse ( ) ; notification . setErrors ( Arrays . asList ( error ) ) ; return notification ; }


Input: Map and SSP Response to a NotificationResponse . [CODESPLIT] private NotificationResponse mapToNotificationResponse ( PortletRequest request , ResponseEntity < String > response ) { Configuration config = Configuration . builder ( ) . options ( Option . DEFAULT_PATH_LEAF_TO_NULL ) . build ( ) ; ReadContext readContext = JsonPath . using ( config ) . parse ( response . getBody ( ) ) ; // check the status embedded in the response too... String success = readContext . read ( SUCCESS_QUERY ) ; // grr. SSP returns this as a string... if ( ! "true" . equalsIgnoreCase ( success ) ) { String error = readContext . read ( MESSAGE_QUERY ) ; return notificationError ( error ) ; } // read the actual tasks... Object rows = readContext . read ( ROWS_QUERY ) ; if ( ! ( rows instanceof JSONArray ) ) { throw new RuntimeException ( "Expected 'rows' to be an array of tasks" ) ; } String source = getNotificationSource ( request ) ; List < NotificationEntry > list = new ArrayList <> ( ) ; for ( int i = 0 ; i < ( ( JSONArray ) rows ) . size ( ) ; i ++ ) { NotificationEntry entry = mapNotificationEntry ( readContext , i , source ) ; if ( entry != null ) { attachActions ( request , entry ) ; list . add ( entry ) ; } } // build the notification response... NotificationResponse notification = new NotificationResponse ( ) ; if ( ! list . isEmpty ( ) ) { NotificationCategory category = getNotificationCategory ( request ) ; category . addEntries ( list ) ; notification . setCategories ( Arrays . asList ( category ) ) ; } return notification ; }


Input: Map a single notification entry . [CODESPLIT] private NotificationEntry mapNotificationEntry ( ReadContext readContext , int index , String source ) { boolean completed = readContext . read ( format ( ROW_COMPLETED_QUERY_FMT , index ) , Boolean . class ) ; if ( completed ) { return null ; } NotificationEntry entry = new NotificationEntry ( ) ; entry . setSource ( source ) ; String id = readContext . read ( format ( ROW_ID_QUERY_FMT , index ) ) ; entry . setId ( id ) ; String title = readContext . read ( format ( ROW_NAME_QUERY_FMT , index ) ) ; entry . setTitle ( title ) ; String desc = readContext . read ( format ( ROW_DESCRIPTION_QUERY_FMT , index ) ) ; entry . setBody ( desc ) ; String link = readContext . read ( format ( ROW_LINK_QUERY_FMT , index ) ) ; URL fixedLink = normalizeLink ( link ) ; if ( fixedLink != null ) { entry . setUrl ( fixedLink . toExternalForm ( ) ) ; } Date createDate = readContext . read ( format ( "$.rows[%d].createdDate" , index ) , Date . class ) ; Map < NotificationState , Date > states = new HashMap <> ( ) ; states . put ( NotificationState . ISSUED , createDate ) ; try { // the date is in an odd format, need to parse by hand... String dateStr = readContext . read ( format ( ROW_DUE_DATE_QUERY_FMT , index ) ) ; if ( ! StringUtils . isBlank ( dateStr ) ) { synchronized ( dateFormat ) { Date dueDate = dateFormat . parse ( dateStr ) ; entry . setDueDate ( dueDate ) ; } } } catch ( Exception e ) { log . warn ( "Error parsing due date.  Ignoring" , e ) ; } return entry ; }


Input: Attach any SSP specific actions to this entry if enabled . [CODESPLIT] private void attachActions ( PortletRequest request , NotificationEntry entry ) { PortletPreferences prefs = request . getPreferences ( ) ; String stringVal = prefs . getValue ( SSP_NOTIFICATIONS_ENABLE_MARK_COMPLETED , "false" ) ; boolean enableMarkCompleted = ( "true" . equalsIgnoreCase ( stringVal ) ) ; List < NotificationAction > actions = new ArrayList <> ( ) ; if ( enableMarkCompleted ) { MarkTaskCompletedAction action = new MarkTaskCompletedAction ( entry . getId ( ) ) ; actions . add ( action ) ; } entry . setAvailableActions ( actions ) ; }


Input: Some of the links I have seen from SSP are not well formed . Try to convert any URLs to a usable form . [CODESPLIT] private URL normalizeLink ( String link ) { try { if ( StringUtils . isEmpty ( link ) ) { return null ; } if ( link . startsWith ( "/" ) ) { return sspApi . getSSPUrl ( link , true ) ; } if ( link . startsWith ( "http://" ) || link . startsWith ( "https://" ) ) { return new URL ( link ) ; } // if all else fails, just tack on http:// and see if the URL parser can handle // it.  Perhaps, not ideal... return new URL ( "http://" + link ) ; } catch ( MalformedURLException e ) { log . warn ( "Bad URL from SSP Entry: " + link , e ) ; return null ; } }


Input: Get the category name to use for SSP notifications . [CODESPLIT] private NotificationCategory getNotificationCategory ( PortletRequest request ) { PortletPreferences preferences = request . getPreferences ( ) ; String title = preferences . getValue ( NOTIFICATION_CATEGORY_PREF , DEFAULT_CATEGORY ) ; NotificationCategory category = new NotificationCategory ( ) ; category . setTitle ( title ) ; return category ; }


Input: Get the source value to use for a Notification entry . [CODESPLIT] private String getNotificationSource ( PortletRequest req ) { PortletPreferences preferences = req . getPreferences ( ) ; String source = preferences . getValue ( NOTIFICATION_SOURCE_PREF , DEFAULT_NOTIFICATION_SOURCE ) ; return source ; }


Input: / * Implementation [CODESPLIT] private String evaluateRedirectUri ( ActionRequest req ) { // Default response -- specify a relative URI, allowing the protocol to be inferred String rslt = req . getContextPath ( ) + SUCCESS_PATH ; final PortletPreferences prefs = req . getPreferences ( ) ; final String protocol = prefs . getValue ( INVOKE_REDIRECT_PROTOCOL_PREFERENCE , null ) ; if ( protocol != null ) { // Specify an absolute URI.  Apparently we need to insist on a protoco (usually HTTPS) String portPart = "" ; // default final String port = prefs . getValue ( INVOKE_REDIRECT_PORT_PREFERENCE , null ) ; if ( port != null ) { portPart = ":" + port ; } rslt = protocol . toLowerCase ( ) + "://" + req . getServerName ( ) // Server hostname + portPart // Server port (blank, with any luck) + rslt ; // Remainder of the URI (as above) } return rslt ; }


Input: Invoking a ReadAction toggles it . [CODESPLIT] @ Override public void invoke ( final ActionRequest req , final ActionResponse res ) throws IOException { final NotificationEntry entry = getTarget ( ) ; final String notificationId = entry . getId ( ) ; final Set < String > readNotices = this . getReadNotices ( req ) ; if ( readNotices . contains ( notificationId ) ) { readNotices . remove ( notificationId ) ; } else { readNotices . add ( notificationId ) ; } setReadNotices ( req , readNotices ) ; }


Input: / * package - private [CODESPLIT] Set < String > getReadNotices ( final PortletRequest req ) { final HashSet < String > rslt = new HashSet <> ( ) ; final PortletPreferences prefs = req . getPreferences ( ) ; final String [ ] ids = prefs . getValues ( READ_NOTIFICATION_IDS_PREFERENCE , new String [ 0 ] ) ; for ( int i = 0 ; i < ids . length ; i ++ ) { rslt . add ( ids [ i ] ) ; } return rslt ; }


Input: When invoke is called a configured notification state is set for the entry if it has not already been set . { @link JpaNotificationService } and { @link CacheNotificationService } are used here to add the entry state and clear the cache for the user . This class is not managed by Spring so these objects must be obtained using the Spring context that { @code SpringContext } provides . [CODESPLIT] @ Override public void invoke ( final ActionRequest req , final ActionResponse res ) throws IOException { JpaNotificationService jpaService = ( JpaNotificationService ) SpringContext . getApplicationContext ( ) . getBean ( "jpaNotificationService" ) ; final NotificationEntry entry = getTarget ( ) ; Map < NotificationState , Date > stateMap = entry . getStates ( ) ; if ( stateMap != null && ! stateMap . containsKey ( NotificationState . COMPLETED ) ) { jpaService . addEntryState ( req , entry . getId ( ) , NotificationState . COMPLETED ) ; } res . sendRedirect ( entry . getUrl ( ) ) ; }


Input: / * Implementation [CODESPLIT] private NotificationResponse fetchFromClasspath ( List < String > locations ) { if ( locations . isEmpty ( ) ) { return NotificationResponse . EMPTY_RESPONSE ; } NotificationResponse rslt ; final Element m = cache . get ( locations ) ; if ( m != null ) { // ## CACHE HIT ## rslt = ( NotificationResponse ) m . getObjectValue ( ) ; logger . debug ( "Locations cache HIT for collection {};  size={}" , locations , rslt . size ( ) ) ; } else { // ## CACHE MISS ## rslt = new NotificationResponse ( ) ; for ( String loc : locations ) { final NotificationResponse response = readFromFile ( loc ) ; rslt = rslt . combine ( response ) ; } logger . debug ( "Locations cache MISS for collection {};  size={}" , locations , rslt . size ( ) ) ; cache . put ( new Element ( locations , rslt ) ) ; } return rslt ; }


Input: Deserialize the given JSON formatted file back into a object . [CODESPLIT] private NotificationResponse readFromFile ( String filename ) { NotificationResponse rslt ; logger . debug ( "Preparing to read from file:  {}" , filename ) ; URL location = getClass ( ) . getClassLoader ( ) . getResource ( filename ) ; if ( location != null ) { try { File f = new File ( location . toURI ( ) ) ; rslt = mapper . readValue ( f , NotificationResponse . class ) ; } catch ( Exception e ) { String msg = "Failed to read the data file:  " + location ; logger . error ( msg , e ) ; rslt = prepareErrorResponse ( getName ( ) , msg ) ; } } else { String msg = "Data file not found:  " + filename ; rslt = prepareErrorResponse ( getName ( ) , msg ) ; } return rslt ; }


Input: / * Implementation [CODESPLIT] private NotificationResponse getResponseFromService ( PortletRequest req , INotificationService service ) { NotificationResponse rslt ; try { rslt = service . fetch ( req ) ; } catch ( Exception e ) { final String msg = "Failed to invoke the specified service:  " + service . getName ( ) ; logger . error ( msg , e ) ; rslt = prepareErrorResponse ( getName ( ) , msg ) ; } return rslt ; }


Input: { [CODESPLIT] @ Override public String lookupPersonId ( PortletRequest request ) { String studentId = getSchoolId ( request ) ; if ( StringUtils . isBlank ( studentId ) ) { return null ; } Element element = cache . get ( studentId ) ; if ( element != null ) { return ( String ) element . getObjectValue ( ) ; } String url = getPersonSearchURL ( ) ; SSPApiRequest sspReq = new SSPApiRequest ( url , String . class ) . addUriParameter ( "schoolId" , studentId ) ; try { ResponseEntity < String > response = sspApi . doRequest ( sspReq ) ; String userId = extractUserId ( studentId , response ) ; Element cacheElement = new Element ( studentId , userId ) ; cache . put ( cacheElement ) ; return userId ; } catch ( Exception e ) { log . error ( e . getMessage ( ) , e ) ; return null ; } }


Input: Get the schoolId value from the request . [CODESPLIT] private String getSchoolId ( PortletRequest request ) { PortletPreferences prefs = request . getPreferences ( ) ; String schoolIdAttributeName = prefs . getValue ( "SSPTaskNotificationService.schoolIdAttribute" , "schoolId" ) ; Map < String , String > userInfo = ( Map < String , String > ) request . getAttribute ( PortletRequest . USER_INFO ) ; String studentId = userInfo . get ( schoolIdAttributeName ) ; if ( ! StringUtils . isEmpty ( studentId ) ) { return studentId ; } // if not found, fall back to username. studentId = userInfo . get ( USERNAME_ATTRIBUTE ) ; return studentId ; }


Input: Parse the person lookup response from SSP . [CODESPLIT] private String extractUserId ( String studentId , ResponseEntity < String > response ) { Configuration config = Configuration . builder ( ) . options ( Option . DEFAULT_PATH_LEAF_TO_NULL ) . build ( ) ; ReadContext readContext = JsonPath . using ( config ) . parse ( response . getBody ( ) ) ; String success = readContext . read ( SUCCESS_QUERY ) ; // SSP passes this as a string... if ( ! "true" . equalsIgnoreCase ( success ) ) { return null ; } int count = readContext . read ( RESULTS_QUERY , Integer . class ) ; if ( count != 1 ) { // couldn't find a single unique result.  Bail now... log . warn ( "Expected a single unique result for " + studentId + ".  Found " + count ) ; return null ; } String id = readContext . read ( STUDENT_ID_QUERY ) ; return id ; }


Input: This { @link INotificationService } is fundamentally about Java Portlets and there is nothing it can offer to this overload of <code > fetch< / code > . [CODESPLIT] @ Override public NotificationResponse fetch ( HttpServletRequest request ) { logger . trace ( "{} invoked for user '{}', but there is nothing to do" , getClass ( ) . getSimpleName ( ) , usernameFinder . findUsername ( request ) ) ; return NotificationResponse . EMPTY_RESPONSE ; }


Input:
Invoking a HideAction toggles it . [CODESPLIT] @ Override public void invoke ( final ActionRequest req , final ActionResponse res ) throws IOException { final NotificationEntry entry = getTarget ( ) ; /*
         * The HideAction works like a toggle
         */ if ( ! isEntrySnoozed ( entry , req ) ) { // Hide it... hide ( entry , req ) ; } else { // Un-hide it... unhide ( entry , req ) ; } }


Input:
/ * package - private [CODESPLIT] long calculateHideDurationMillis ( final NotificationEntry entry , final PortletRequest req ) { /*
         * A notification may specify it's own duration as an attribute;
         * if it doesn't, there is a default from the (portlet) publication record.
         */ final PortletPreferences prefs = req . getPreferences ( ) ; // This is the default String hideDurationHours = prefs . getValue ( HideNotificationServiceDecorator . HIDE_DURATION_HOURS_PREFERENCE , null ) ; // Duration specified on the entry itself will trump final Map < String , List < String > > attributes = entry . getAttributesMap ( ) ; if ( attributes . containsKey ( HIDE_DURATION_HOURS_ATTRIBUTE_NAME ) ) { final List < String > values = attributes . get ( HIDE_DURATION_HOURS_ATTRIBUTE_NAME ) ; if ( values . size ( ) != 0 ) { hideDurationHours = values . get ( 0 ) ; // First is the only one that matters } } final long rslt = hideDurationHours != null ? Long . parseLong ( hideDurationHours ) * MILLIS_IN_ONE_HOUR : HideNotificationServiceDecorator . HIDE_DURATION_NONE ; logger . debug ( "Calculated calculateHideDurationMillis={} for entry with id='{}', title='{}'" , rslt , entry . getId ( ) , entry . getTitle ( ) ) ; return rslt ; }


Input: / * package - private [CODESPLIT] boolean isEntrySnoozed ( NotificationEntry entry , PortletRequest req ) { // An id is required for hide behavior if ( StringUtils . isBlank ( entry . getId ( ) ) ) { return false ; } boolean rslt = false ; // default (clearly) final long snoozeDurationMillis = calculateHideDurationMillis ( entry , req ) ; // An entry with a negative snooze duration cannot be snoozed if ( snoozeDurationMillis > HideNotificationServiceDecorator . HIDE_DURATION_NONE ) { final JpaServices jpaServices = ( JpaServices ) SpringContext . getApplicationContext ( ) . getBean ( "jpaServices" ) ; final List < EventDTO > history = jpaServices . getHistory ( entry , req . getRemoteUser ( ) ) ; logger . debug ( "List<EventDTO> within getNotificationsBySourceAndCustomAttribute contains {} elements" , history . size ( ) ) ; // Review the history... for ( EventDTO event : history ) { switch ( event . getState ( ) ) { case SNOOZED : logger . debug ( "Found a SNOOZED event:  {}" , event ) ; // Nice, but it only counts if it isn't expired... if ( event . getTimestamp ( ) . getTime ( ) + snoozeDurationMillis > System . currentTimeMillis ( ) ) { rslt = true ; } break ; case ISSUED : logger . debug ( "Found an ISSUED event:  {}" , event ) ; // Re-issuing a notification un-snoozes it... rslt = false ; break ; default : // We don't care about any other events in the SNOOZED evaluation... break ; } } } logger . debug ( "Returning SNOOZED='{}' for the following notification:  {}" , rslt , entry ) ; return rslt ; }


Input: / * Implementation [CODESPLIT] private void hide ( NotificationEntry entry , ActionRequest req ) { final JpaServices jpaServices = ( JpaServices ) SpringContext . getApplicationContext ( ) . getBean ( "jpaServices" ) ; jpaServices . applyState ( entry , req . getRemoteUser ( ) , NotificationState . SNOOZED ) ; }


Input: Convenience method for obtaining the attributes in a more usable collection . [CODESPLIT] @ JsonIgnore public Map < String , List < String > > getAttributesMap ( ) { Map < String , List < String > > rslt = new HashMap <> ( ) ; for ( NotificationAttribute a : attributes ) { rslt . put ( a . getName ( ) , a . getValues ( ) ) ; } return rslt ; }


Input: Normalizes the point such that the Frobenius norm is 1 . [CODESPLIT] public static void normalize ( GeoTuple3D_F64 p ) { double n = p . norm ( ) ; p . x /= n ; p . y /= n ; p . z /= n ; }


Input: Returns true if the point is contained inside the box . The point is considered to be inside the box if the following test passes for each dimension . box . p0 . x &le ; point . x { @code < } box . p1 . x + box . lengthX [CODESPLIT] public static boolean contained ( Box3D_I32 box , Point3D_I32 point ) { return ( box . p0 . x <= point . x && point . x < box . p1 . x && box . p0 . y <= point . y && point . y < box . p1 . y && box . p0 . z <= point . z && point . z < box . p1 . z ) ; }


Input: Returns true if boxB is contained inside of or is identical to boxA . [CODESPLIT] public static boolean contained ( Box3D_I32 boxA , Box3D_I32 boxB ) { return ( boxA . p0 . x <= boxB . p0 . x && boxA . p1 . x >= boxB . p1 . x && boxA . p0 . y <= boxB . p0 . y && boxA . p1 . y >= boxB . p1 . y && boxA . p0 . z <= boxB . p0 . z && boxA . p1 . z >= boxB . p1 . z ) ; }


Input: Find the closest point on the triangle to P . [CODESPLIT] public void closestPoint ( Point3D_F64 P , Point3D_F64 closestPt ) { // D = B-P GeometryMath_F64 . sub ( B , P , D ) ; a = E0 . dot ( E0 ) ; b = E0 . dot ( E1 ) ; c = E1 . dot ( E1 ) ; d = E0 . dot ( D ) ; e = E1 . dot ( D ) ; double det = a * c - b * b ; s = b * e - c * d ; t = b * d - a * e ; if ( s + t <= det ) { if ( s < 0 ) { if ( t < 0 ) { region4 ( ) ; } else { region3 ( ) ; } } else if ( t < 0 ) { region5 ( ) ; } else { region0 ( det ) ; } } else { if ( s < 0 ) { region2 ( ) ; } else if ( t < 0 ) { region6 ( ) ; } else { region1 ( ) ; } } closestPt . x = B . x + s * E0 . x + t * E1 . x ; closestPt . y = B . y + s * E0 . y + t * E1 . y ; closestPt . z = B . z + s * E0 . z + t * E1 . z ; }


Input: Returns the signed of the vector . If its in front it will be positive and negative if behind . In front is defined as being on the same side as the cross product of p2 - p0 and p1 - p0 . [CODESPLIT] public double sign ( Point3D_F64 P ) { GeometryMath_F64 . cross ( E1 , E0 , N ) ; // dot product of double d = N . x * ( P . x - B . x ) + N . y * ( P . y - B . y ) + N . z * ( P . z - B . z ) ; return Math . signum ( d ) ; }


Input: Set s this Se3_F64 to be identical to the provided transform . [CODESPLIT] public void set ( Se3_F64 se ) { R . set ( se . getR ( ) ) ; T . set ( se . getT ( ) ) ; }


Input: Fully specify the transform using Euler angles [CODESPLIT] public void set ( double x , double y , double z , EulerType type , double rotA , double rotB , double rotC ) { T . set ( x , y , z ) ; ConvertRotation3D_F64 . eulerToMatrix ( type , rotA , rotB , rotC , R ) ; }


Input: Fully specifies the transform using Rodrigues ( axis angle ) or Quaternions . If Rodrigues then A = axisX B = axisY C = axisZ D = theta . If Quaternion then A = w B = x C = y D = z . [CODESPLIT] public void set ( double x , double y , double z , RotationType type , double A , double B , double C , double D ) { T . set ( x , y , z ) ; switch ( type ) { case RODRIGUES : ConvertRotation3D_F64 . rodriguesToMatrix ( A , B , C , D , R ) ; break ; case QUATERNION : ConvertRotation3D_F64 . quaternionToMatrix ( A , B , C , D , R ) ; break ; default : throw new IllegalArgumentException ( "Type is not supported. " + type ) ; } }


Input: Applies the transform to the src point and stores the result in dst . src and dst can be the same instance [CODESPLIT] public Point3D_F64 transform ( Point3D_F64 src , @ Nullable Point3D_F64 dst ) { return SePointOps_F64 . transform ( this , src , dst ) ; }


Input: Applies the reverse transform to the src point and stores the result in dst . src and dst can be the same instance [CODESPLIT] public Point3D_F64 transformReverse ( Point3D_F64 src , @ Nullable Point3D_F64 dst ) { return SePointOps_F64 . transformReverse ( this , src , dst ) ; }


Input: Applies the rotation to the src vector and stores the result in dst . src and dst can be the same instance [CODESPLIT] public Vector3D_F64 transform ( Vector3D_F64 src , @ Nullable Vector3D_F64 dst ) { return GeometryMath_F64 . mult ( R , src , dst ) ; }


Input: Applies the reverse rotation to the src vector and stores the result in dst . src and dst can be the same instance [CODESPLIT] public Vector3D_F64 transformReverse ( Vector3D_F64 src , @ Nullable Vector3D_F64 dst ) { return GeometryMath_F64 . multTran ( R , src , dst ) ; }


Input: Converts a rectangle into a quadrilateral [CODESPLIT] public static void convert ( Rectangle2D_F64 input , Quadrilateral_F64 output ) { output . a . x = input . p0 . x ; output . a . y = input . p0 . y ; output . b . x = input . p1 . x ; output . b . y = input . p0 . y ; output . c . x = input . p1 . x ; output . c . y = input . p1 . y ; output . d . x = input . p0 . x ; output . d . y = input . p1 . y ; }


Input: Converts a rectangle into a polygon [CODESPLIT] public static void convert ( Rectangle2D_F64 input , Polygon2D_F64 output ) { if ( output . size ( ) != 4 ) throw new IllegalArgumentException ( "polygon of order 4 expected" ) ; output . get ( 0 ) . set ( input . p0 . x , input . p0 . y ) ; output . get ( 1 ) . set ( input . p1 . x , input . p0 . y ) ; output . get ( 2 ) . set ( input . p1 . x , input . p1 . y ) ; output . get ( 3 ) . set ( input . p0 . x , input . p1 . y ) ; }


Input: Converts a polygon into a quadrilateral [CODESPLIT] public static void convert ( Polygon2D_F64 input , Quadrilateral_F64 output ) { if ( input . size ( ) != 4 ) throw new IllegalArgumentException ( "Expected 4-sided polygon as input" ) ; output . a . set ( input . get ( 0 ) ) ; output . b . set ( input . get ( 1 ) ) ; output . c . set ( input . get ( 2 ) ) ; output . d . set ( input . get ( 3 ) ) ; }


Input: Converts a rectangle into a quadrilateral [CODESPLIT] public static void convert ( RectangleLength2D_I32 input , Quadrilateral_F64 output ) { output . a . x = input . x0 ; output . a . y = input . y0 ; output . b . x = input . x0 + input . width - 1 ; output . b . y = input . y0 ; output . c . x = input . x0 + input . width - 1 ; output . c . y = input . y0 + input . height - 1 ; output . d . x = input . x0 ; output . d . y = input . y0 + input . height - 1 ; }


Input: Finds the minimum area bounding rectangle around the quadrilateral . [CODESPLIT] public static void bounding ( Quadrilateral_F64 quad , Rectangle2D_F64 rectangle ) { rectangle . p0 . x = Math . min ( quad . a . x , quad . b . x ) ; rectangle . p0 . x = Math . min ( rectangle . p0 . x , quad . c . x ) ; rectangle . p0 . x = Math . min ( rectangle . p0 . x , quad . d . x ) ; rectangle . p0 . y = Math . min ( quad . a . y , quad . b . y ) ; rectangle . p0 . y = Math . min ( rectangle . p0 . y , quad . c . y ) ; rectangle . p0 . y = Math . min ( rectangle . p0 . y , quad . d . y ) ; rectangle . p1 . x = Math . max ( quad . a . x , quad . b . x ) ; rectangle . p1 . x = Math . max ( rectangle . p1 . x , quad . c . x ) ; rectangle . p1 . x = Math . max ( rectangle . p1 . x , quad . d . x ) ; rectangle . p1 . y = Math . max ( quad . a . y , quad . b . y ) ; rectangle . p1 . y = Math . max ( rectangle . p1 . y , quad . c . y ) ; rectangle . p1 . y = Math . max ( rectangle . p1 . y , quad . d . y ) ; }


Input: Finds the minimum area bounding rectangle around the quadrilateral that is aligned with coordinate system axises . [CODESPLIT] public static void bounding ( Polygon2D_F64 polygon , Rectangle2D_F64 rectangle ) { rectangle . p0 . set ( polygon . get ( 0 ) ) ; rectangle . p1 . set ( polygon . get ( 0 ) ) ; for ( int i = 0 ; i < polygon . size ( ) ; i ++ ) { Point2D_F64 p = polygon . get ( i ) ; if ( p . x < rectangle . p0 . x ) { rectangle . p0 . x = p . x ; } else if ( p . x > rectangle . p1 . x ) { rectangle . p1 . x = p . x ; } if ( p . y < rectangle . p0 . y ) { rectangle . p0 . y = p . y ; } else if ( p . y > rectangle . p1 . y ) { rectangle . p1 . y = p . y ; } } }


Input: Computes the center or average point in the quadrilateral . [CODESPLIT] public static Point2D_F64 center ( Quadrilateral_F64 quad , Point2D_F64 center ) { if ( center == null ) center = new Point2D_F64 ( ) ; center . x = quad . a . x + quad . b . x + quad . c . x + quad . d . x ; center . y = quad . a . y + quad . b . y + quad . c . y + quad . d . y ; center . x /= 4.0 ; center . y /= 4.0 ; return center ; }


Input: Returns true if the polygon is ordered in a counter - clockwise order . This is done by summing up the interior angles . [CODESPLIT] public static boolean isCCW ( List < Point2D_F64 > polygon ) { final int N = polygon . size ( ) ; int sign = 0 ; for ( int i = 0 ; i < N ; i ++ ) { int j = ( i + 1 ) % N ; int k = ( i + 2 ) % N ; Point2D_F64 a = polygon . get ( i ) ; Point2D_F64 b = polygon . get ( j ) ; Point2D_F64 c = polygon . get ( k ) ; double dx0 = a . x - b . x ; double dy0 = a . y - b . y ; double dx1 = c . x - b . x ; double dy1 = c . y - b . y ; double z = dx0 * dy1 - dy0 * dx1 ; if ( z > 0 ) sign ++ ; else sign -- ; } return sign < 0 ; }


Input: Computes the average of all the vertexes [CODESPLIT] public static void vertexAverage ( Polygon2D_F64 input , Point2D_F64 average ) { average . setIdx ( 0 , 0 ) ; for ( int i = 0 ; i < input . size ( ) ; i ++ ) { Point2D_F64 v = input . vertexes . data [ i ] ; average . x += v . x ; average . y += v . y ; } average . x /= input . size ( ) ; average . y /= input . size ( ) ; }


Input: Checks to see if the vertexes of the two polygon s are the same up to the specified tolerance [CODESPLIT] public static boolean isIdentical ( Polygon2D_F64 a , Polygon2D_F64 b , double tol ) { if ( a . size ( ) != b . size ( ) ) return false ; double tol2 = tol * tol ; for ( int i = 0 ; i < a . size ( ) ; i ++ ) { if ( a . get ( i ) . distance2 ( b . get ( i ) ) > tol2 ) return false ; } return true ; }


Input: Checks to see if the vertexes of the two polygon s are the same up to the specified tolerance and allows for a shift in their order [CODESPLIT] public static boolean isEquivalent ( Polygon2D_F64 a , Polygon2D_F64 b , double tol ) { if ( a . size ( ) != b . size ( ) ) return false ; double tol2 = tol * tol ; // first find two vertexes which are the same Point2D_F64 a0 = a . get ( 0 ) ; int match = - 1 ; for ( int i = 0 ; i < b . size ( ) ; i ++ ) { if ( a0 . distance2 ( b . get ( i ) ) <= tol2 ) { match = i ; break ; } } if ( match < 0 ) return false ; // now go in a circle and see if they all line up for ( int i = 1 ; i < b . size ( ) ; i ++ ) { Point2D_F64 ai = a . get ( i ) ; Point2D_F64 bi = b . get ( ( match + i ) % b . size ( ) ) ; if ( ai . distance2 ( bi ) > tol2 ) { return false ; } } return true ; }


Input: Flips the order of points inside the polygon . The first index will remain the same will otherwise be reversed [CODESPLIT] public static void flip ( Polygon2D_F64 a ) { int N = a . size ( ) ; int H = N / 2 ; for ( int i = 1 ; i <= H ; i ++ ) { int j = N - i ; Point2D_F64 tmp = a . vertexes . data [ i ] ; a . vertexes . data [ i ] = a . vertexes . data [ j ] ; a . vertexes . data [ j ] = tmp ; } }


Input: Shifts all the vertexes in the polygon up one element . Wraps around at the end [CODESPLIT] public static void shiftUp ( Polygon2D_F64 a ) { final int N = a . size ( ) ; Point2D_F64 first = a . get ( 0 ) ; for ( int i = 0 ; i < N - 1 ; i ++ ) { a . vertexes . data [ i ] = a . vertexes . data [ i + 1 ] ; } a . vertexes . data [ N - 1 ] = first ; }


Input: Shifts all the vertexes in the polygon up one element . Wraps around at the end [CODESPLIT] public static void shiftDown ( Polygon2D_F64 a ) { final int N = a . size ( ) ; Point2D_F64 last = a . get ( N - 1 ) ; for ( int i = N - 1 ; i > 0 ; i -- ) { a . vertexes . data [ i ] = a . vertexes . data [ i - 1 ] ; } a . vertexes . data [ 0 ] = last ; }


Input: Computes the convex hull of the set of points . [CODESPLIT] public static void convexHull ( List < Point2D_F64 > points , Polygon2D_F64 hull ) { Point2D_F64 [ ] array = new Point2D_F64 [ points . size ( ) ] ; for ( int i = 0 ; i < points . size ( ) ; i ++ ) { array [ i ] = points . get ( i ) ; } AndrewMonotoneConvexHull_F64 andrew = new AndrewMonotoneConvexHull_F64 ( ) ; andrew . process ( array , array . length , hull ) ; }


Input: Removes a node from a polygon if the two lines its attached two are almost parallel [CODESPLIT] public static void removeAlmostParallel ( Polygon2D_F64 polygon , double tol ) { for ( int i = 0 ; i < polygon . vertexes . size ( ) ; ) { int j = ( i + 1 ) % polygon . vertexes . size ( ) ; int k = ( i + 2 ) % polygon . vertexes . size ( ) ; Point2D_F64 p0 = polygon . vertexes . get ( i ) ; Point2D_F64 p1 = polygon . vertexes . get ( j ) ; Point2D_F64 p2 = polygon . vertexes . get ( k ) ; double angle = UtilVector2D_F64 . acute ( p1 . x - p0 . x , p1 . y - p0 . y , p2 . x - p1 . x , p2 . y - p1 . y ) ; if ( angle <= tol ) { polygon . vertexes . remove ( j ) ; if ( j < i ) i = polygon . vertexes . size ( ) - 1 ; } else { i ++ ; } } }


Input: Remove a point if it s identical to a neighbor [CODESPLIT] public static void removeAdjacentDuplicates ( Polygon2D_F64 polygon , double tol ) { for ( int i = polygon . vertexes . size ( ) - 1 , j = 0 ; i >= 0 && polygon . size ( ) > 1 ; j = i , i -- ) { if ( polygon . get ( i ) . isIdentical ( polygon . get ( j ) , tol ) ) { polygon . vertexes . remove ( i ) ; } } }


Input: Remove a point if it s identical to a neighbor [CODESPLIT] public static boolean hasAdjacentDuplicates ( Polygon2D_F64 polygon , double tol ) { for ( int i = polygon . vertexes . size ( ) - 1 , j = 0 ; i >= 0 && polygon . size ( ) > 1 ; j = i , i -- ) { if ( polygon . get ( i ) . isIdentical ( polygon . get ( j ) , tol ) ) { return true ; } } return false ; }


Input: Compute the error as a function of the distance between the model and target . The target is sampled at regular intervals and for each of these points the closest point on the model is found . The returned metric is the average of difference between paired points . [CODESPLIT] public static double averageOfClosestPointError ( Polygon2D_F64 model , Polygon2D_F64 target , int numberOfSamples ) { LineSegment2D_F64 line = new LineSegment2D_F64 ( ) ; double cornerLocationsB [ ] = new double [ target . size ( ) + 1 ] ; double totalLength = 0 ; for ( int i = 0 ; i < target . size ( ) ; i ++ ) { Point2D_F64 b0 = target . get ( i % target . size ( ) ) ; Point2D_F64 b1 = target . get ( ( i + 1 ) % target . size ( ) ) ; cornerLocationsB [ i ] = totalLength ; totalLength += b0 . distance ( b1 ) ; } cornerLocationsB [ target . size ( ) ] = totalLength ; Point2D_F64 pointOnB = new Point2D_F64 ( ) ; double error = 0 ; int cornerB = 0 ; for ( int k = 0 ; k < numberOfSamples ; k ++ ) { // Find the point on B to match to a point on A double location = totalLength * k / numberOfSamples ; while ( location > cornerLocationsB [ cornerB + 1 ] ) { cornerB ++ ; } Point2D_F64 b0 = target . get ( cornerB ) ; Point2D_F64 b1 = target . get ( ( cornerB + 1 ) % target . size ( ) ) ; double locationCornerB = cornerLocationsB [ cornerB ] ; double fraction = ( location - locationCornerB ) / ( cornerLocationsB [ cornerB + 1 ] - locationCornerB ) ; pointOnB . x = ( b1 . x - b0 . x ) * fraction + b0 . x ; pointOnB . y = ( b1 . y - b0 . y ) * fraction + b0 . y ; // find the best fit point on A to the point in B double best = Double . MAX_VALUE ; for ( int i = 0 ; i < model . size ( ) + 1 ; i ++ ) { line . a = model . get ( i % model . size ( ) ) ; line . b = model . get ( ( i + 1 ) % model . size ( ) ) ; double d = Distance2D_F64 . distance ( line , pointOnB ) ; if ( d < best ) { best = d ; } } error += best ; } return error / numberOfSamples ; }


Input: Converts the provided 3x3 matrix into a { @link Homography2D_F64 } . [CODESPLIT] public static Homography2D_F64 convert ( DMatrixRMaj m , Homography2D_F64 ret ) { if ( m . numCols != 3 || m . numRows != 3 ) throw new IllegalArgumentException ( "Expected a 3 by 3 matrix." ) ; if ( ret == null ) ret = new Homography2D_F64 ( ) ; ret . a11 = m . unsafe_get ( 0 , 0 ) ; ret . a12 = m . unsafe_get ( 0 , 1 ) ; ret . a13 = m . unsafe_get ( 0 , 2 ) ; ret . a21 = m . unsafe_get ( 1 , 0 ) ; ret . a22 = m . unsafe_get ( 1 , 1 ) ; ret . a23 = m . unsafe_get ( 1 , 2 ) ; ret . a31 = m . unsafe_get ( 2 , 0 ) ; ret . a32 = m . unsafe_get ( 2 , 1 ) ; ret . a33 = m . unsafe_get ( 2 , 2 ) ; return ret ; }


Input: Converts a { @link Homography2D_F64 } into a 3x3 matrix . [CODESPLIT] public static DMatrixRMaj convert ( Homography2D_F64 m , DMatrixRMaj ret ) { if ( ret == null ) { ret = new DMatrixRMaj ( 3 , 3 ) ; } else if ( ret . numCols != 3 || ret . numRows != 3 ) throw new IllegalArgumentException ( "Expected a 3 by 3 matrix." ) ; ret . unsafe_set ( 0 , 0 , m . a11 ) ; ret . unsafe_set ( 0 , 1 , m . a12 ) ; ret . unsafe_set ( 0 , 2 , m . a13 ) ; ret . unsafe_set ( 1 , 0 , m . a21 ) ; ret . unsafe_set ( 1 , 1 , m . a22 ) ; ret . unsafe_set ( 1 , 2 , m . a23 ) ; ret . unsafe_set ( 2 , 0 , m . a31 ) ; ret . unsafe_set ( 2 , 1 , m . a32 ) ; ret . unsafe_set ( 2 , 2 , m . a33 ) ; return ret ; }


Input: Computes the area of the intersection between the two polygons . [CODESPLIT] public double computeArea ( Polygon2D_F64 a , Polygon2D_F64 b ) { ssss = 0 ; sclx = 0 ; scly = 0 ; return inter ( a , b ) ; }


Input: ------------------------------------------------------------------------- [CODESPLIT] private double inter ( Polygon2D_F64 a , Polygon2D_F64 b ) { if ( a . size ( ) < 3 || b . size ( ) < 3 ) return 0 ; //		int na = a.size(); //		int nb = b.size(); Vertex [ ] ipa = new Vertex [ a . size ( ) + 1 ] ; Vertex [ ] ipb = new Vertex [ b . size ( ) + 1 ] ; Rectangle2D_F64 bbox = new Rectangle2D_F64 ( Double . MAX_VALUE , Double . MAX_VALUE , - Double . MAX_VALUE , - Double . MAX_VALUE ) ; range ( a , bbox ) ; range ( b , bbox ) ; double rngx = bbox . p1 . x - bbox . p0 . x ; sclx = gamut / rngx ; double rngy = bbox . p1 . y - bbox . p0 . y ; scly = gamut / rngy ; double ascale = sclx * scly ; fit ( a , ipa , 0 , bbox ) ; fit ( b , ipb , 2 , bbox ) ; for ( int j = 0 ; j < a . size ( ) ; ++ j ) { for ( int k = 0 ; k < b . size ( ) ; ++ k ) { if ( ovl ( ipa [ j ] . rx , ipb [ k ] . rx ) && ovl ( ipa [ j ] . ry , ipb [ k ] . ry ) ) { long a1 = - area ( ipa [ j ] . ip , ipb [ k ] . ip , ipb [ k + 1 ] . ip ) ; long a2 = area ( ipa [ j + 1 ] . ip , ipb [ k ] . ip , ipb [ k + 1 ] . ip ) ; boolean o = a1 < 0 ; if ( o == a2 < 0 ) { long a3 = area ( ipb [ k ] . ip , ipa [ j ] . ip , ipa [ j + 1 ] . ip ) ; long a4 = - area ( ipb [ k + 1 ] . ip , ipa [ j ] . ip , ipa [ j + 1 ] . ip ) ; if ( a3 < 0 == a4 < 0 ) { if ( o ) cross ( ipa [ j ] , ipa [ j + 1 ] , ipb [ k ] , ipb [ k + 1 ] , a1 , a2 , a3 , a4 ) ; else cross ( ipb [ k ] , ipb [ k + 1 ] , ipa [ j ] , ipa [ j + 1 ] , a3 , a4 , a1 , a2 ) ; } } } } } inness ( ipa , a . size ( ) , ipb , b . size ( ) ) ; inness ( ipb , b . size ( ) , ipa , a . size ( ) ) ; return ssss / ascale ; }


Input: Returns a point along the line . See parametric equation in class description . [CODESPLIT] public Point2D_F64 getPointOnLine ( double t ) { return new Point2D_F64 ( slopeX * t + p . x , slopeY * t + p . y ) ; }


Input: http : // www . ecse . rpi . edu / Homepages / wrf / Research / Short_Notes / pnpoly . html [CODESPLIT] public static boolean containConvex ( Polygon2D_F64 polygon , Point2D_F64 pt ) { final int N = polygon . size ( ) ; boolean c = false ; for ( int i = 0 , j = N - 1 ; i < N ; j = i ++ ) { Point2D_F64 a = polygon . vertexes . data [ i ] ; Point2D_F64 b = polygon . vertexes . data [ j ] ; if ( ( ( a . y > pt . y ) != ( b . y > pt . y ) ) && ( pt . x < ( b . x - a . x ) * ( pt . y - a . y ) / ( b . y - a . y ) + a . x ) ) c = ! c ; } return c ; }


Input: Checks to see if the point is contained inside the concave polygon . [CODESPLIT] public static boolean containConcave ( Polygon2D_F64 polygon , Point2D_F64 pt ) { final int N = polygon . size ( ) ; int left = 0 ; int right = 0 ; for ( int i = 0 ; i < N - 1 ; i ++ ) { Point2D_F64 a = polygon . vertexes . data [ i ] ; Point2D_F64 b = polygon . vertexes . data [ i + 1 ] ; if ( ( pt . y >= a . y && pt . y < b . y ) || ( pt . y >= b . y && pt . y < a . y ) ) { // location of line segment along x-axis at y = pt.y double x = b . y == a . y ? pt . x : ( pt . y - a . y ) * ( b . x - a . x ) / ( b . y - a . y ) + a . x ; if ( x <= pt . x ) left ++ ; else if ( x > pt . x ) right ++ ; } } Point2D_F64 a = polygon . vertexes . data [ N - 1 ] ; Point2D_F64 b = polygon . vertexes . data [ 0 ] ; if ( ( pt . y >= a . y && pt . y < b . y ) || ( pt . y >= b . y && pt . y < a . y ) ) { // location of line segment along x-axis at y = pt.y double x = b . y == a . y ? pt . x : ( pt . y - pt . y ) * ( b . x - a . x ) / ( b . y - a . y ) + a . x ; if ( x <= pt . x ) left ++ ; else if ( x > pt . x ) right ++ ; } return ( left % 2 == 1 && right % 2 == 1 ) ; }


Input: True if the point is contained inside the quadrilateral . [CODESPLIT] public static boolean contains ( Quadrilateral_F64 quad , Point2D_F64 pt ) { return containTriangle ( quad . a , quad . b , quad . d , pt ) || containTriangle ( quad . b , quad . c , quad . d , pt ) ; }


Input: Returns true of the the point is inside the triangle . [CODESPLIT] public static boolean containTriangle ( Point2D_F64 a , Point2D_F64 b , Point2D_F64 c , Point2D_F64 pt ) { boolean ret = false ; if ( ( ( a . y > pt . y ) != ( b . y > pt . y ) ) && ( pt . x < ( b . x - a . x ) * ( pt . y - a . y ) / ( b . y - a . y ) + a . x ) ) ret = true ; if ( ( ( b . y > pt . y ) != ( c . y > pt . y ) ) && ( pt . x < ( c . x - b . x ) * ( pt . y - b . y ) / ( c . y - b . y ) + b . x ) ) ret = ! ret ; if ( ( ( c . y > pt . y ) != ( a . y > pt . y ) ) && ( pt . x < ( a . x - c . x ) * ( pt . y - c . y ) / ( a . y - c . y ) + c . x ) ) ret = ! ret ; return ret ; }


Input: Finds the point of intersection between two lines and returns the point . [CODESPLIT] public static Point2D_F64 intersection ( LineParametric2D_F64 a , LineParametric2D_F64 b , Point2D_F64 ret ) { double t_b = a . getSlopeX ( ) * ( b . getY ( ) - a . getY ( ) ) - a . getSlopeY ( ) * ( b . getX ( ) - a . getX ( ) ) ; double bottom = a . getSlopeY ( ) * b . getSlopeX ( ) - b . getSlopeY ( ) * a . getSlopeX ( ) ; if ( bottom == 0 ) return null ; t_b /= bottom ; double x = b . getSlopeX ( ) * t_b + b . getX ( ) ; double y = b . getSlopeY ( ) * t_b + b . getY ( ) ; if ( ret == null ) ret = new Point2D_F64 ( ) ; ret . set ( x , y ) ; return ret ; }


Input: Finds the point of intersection between two lines . The point of intersection is specified as a point along the parametric line a . ( x y ) = ( x_0 y_0 ) + t * ( slope_x slope_y ) where t is the location returned . [CODESPLIT] public static double intersection ( LineParametric2D_F64 a , LineParametric2D_F64 b ) { double t_a = b . getSlopeX ( ) * ( a . getY ( ) - b . getY ( ) ) - b . getSlopeY ( ) * ( a . getX ( ) - b . getX ( ) ) ; double bottom = b . getSlopeY ( ) * a . getSlopeX ( ) - a . getSlopeY ( ) * b . getSlopeX ( ) ; if ( bottom == 0 ) return Double . NaN ; return t_a / bottom ; }


Input: Finds the point of intersection between two lines segments . [CODESPLIT] public static Point2D_F64 intersection ( LineSegment2D_F64 l_0 , LineSegment2D_F64 l_1 , Point2D_F64 ret ) { double a0 = l_0 . b . x - l_0 . a . x ; double b0 = l_0 . b . y - l_0 . a . y ; double a1 = l_1 . b . x - l_1 . a . x ; double b1 = l_1 . b . y - l_1 . a . y ; double top = b0 * ( l_1 . a . x - l_0 . a . x ) + a0 * ( l_0 . a . y - l_1 . a . y ) ; double bottom = a0 * b1 - b0 * a1 ; if ( bottom == 0 ) return null ; double t_1 = top / bottom ; // does not intersect along the second line segment if ( t_1 < 0 || t_1 > 1 ) return null ; top = b1 * ( l_0 . a . x - l_1 . a . x ) + a1 * ( l_1 . a . y - l_0 . a . y ) ; bottom = a1 * b0 - b1 * a0 ; double t_0 = top / bottom ; // does not intersect along the first line segment if ( t_0 < 0 || t_0 > 1 ) return null ; if ( ret == null ) { ret = new Point2D_F64 ( ) ; } ret . set ( l_1 . a . x + a1 * t_1 , l_1 . a . y + b1 * t_1 ) ; return ret ; }


Input: <p > Finds the intersection of two lines as a 2D point in homogeneous coordinates . Because the solution is found in homogeneous coordinates it can even handle parallel lines which intersect at infinity . < / p > [CODESPLIT] public static Point3D_F64 intersection ( LineGeneral2D_F64 a , LineGeneral2D_F64 b , Point3D_F64 ret ) { if ( ret == null ) ret = new Point3D_F64 ( ) ; // compute the intersection as the cross product of 'a' and 'b' ret . x = a . B * b . C - a . C * b . B ; ret . y = a . C * b . A - a . A * b . C ; ret . z = a . A * b . B - a . B * b . A ; return ret ; }


Input: Finds the point of intersection between the two lines defined by the set sets of points passed in . [CODESPLIT] public static Point2D_F64 intersection ( Point2D_F64 lineA0 , Point2D_F64 lineA1 , Point2D_F64 lineB0 , Point2D_F64 lineB1 , Point2D_F64 output ) { if ( output == null ) output = new Point2D_F64 ( ) ; double slopeAx = lineA1 . x - lineA0 . x ; double slopeAy = lineA1 . y - lineA0 . y ; double slopeBx = lineB1 . x - lineB0 . x ; double slopeBy = lineB1 . y - lineB0 . y ; double top = slopeAy * ( lineB0 . x - lineA0 . x ) + slopeAx * ( lineA0 . y - lineB0 . y ) ; double bottom = slopeAx * slopeBy - slopeAy * slopeBx ; if ( bottom == 0 ) return null ; double t = top / bottom ; output . x = lineB0 . x + t * slopeBx ; output . y = lineB0 . y + t * slopeBy ; return output ; }


Input: Finds the point of intersection between a line and a line segment . The point of intersection is specified as the distance along the parametric line . If no intersection is found then Double . NaN is returned . [CODESPLIT] public static double intersection ( LineParametric2D_F64 target , LineSegment2D_F64 l ) { double a1 = l . b . x - l . a . x ; double b1 = l . b . y - l . a . y ; double top = target . slope . y * ( l . a . x - target . p . x ) + target . slope . x * ( target . p . y - l . a . y ) ; double bottom = target . slope . x * b1 - target . slope . y * a1 ; if ( bottom == 0 ) return Double . NaN ; double t_1 = top / bottom ; // does not intersect along the second line segment if ( t_1 < 0 || t_1 > 1 ) return Double . NaN ; top = b1 * ( target . p . x - l . a . x ) + a1 * ( l . a . y - target . p . y ) ; bottom = a1 * target . slope . y - b1 * target . slope . x ; return top / bottom ; }


Input: Finds the area of the intersection of two polygons . [CODESPLIT] public static double intersection ( Polygon2D_F64 a , Polygon2D_F64 b ) { AreaIntersectionPolygon2D_F64 alg = new AreaIntersectionPolygon2D_F64 ( ) ; return Math . abs ( alg . computeArea ( a , b ) ) ; }


Input: <p > Checks to see if the specified point is inside the rectangle . A point is inside if it is &ge ; the lower extend and &lt ; the upper extent . < / p > <p > inside = x &ge ; x0 AND x &le ; x1 AND y &ge ; y0 AND y &le ; y1 < / p > [CODESPLIT] public static boolean contains ( Rectangle2D_F64 a , double x , double y ) { return ( a . p0 . x <= x && a . p1 . x > x && a . p0 . y <= y && a . p1 . y > y ) ; }


Input: <p > Checks to see if the specified point is inside the rectangle . A point is inside if it is &ge ; the lower extend and &le ; the upper extent . < / p > <p > inside = x &ge ; x0 AND x &le ; x1 AND y &ge ; y0 AND y &le ; y1 < / p > [CODESPLIT] public static boolean contains2 ( Rectangle2D_F64 a , double x , double y ) { return ( a . p0 . x <= x && a . p1 . x >= x && a . p0 . y <= y && a . p1 . y >= y ) ; }


Input: Tests to see if the provided point lies on or is contained inside the ellipse [CODESPLIT] public static boolean contains ( EllipseRotated_F64 ellipse , double x , double y ) { return ( UtilEllipse_F64 . evaluate ( x , y , ellipse ) <= 1.0 ) ; }


Input: Checks to see if the two rectangles intersect each other [CODESPLIT] public static boolean intersects ( Rectangle2D_F64 a , Rectangle2D_F64 b ) { return ( a . p0 . x < b . p1 . x && a . p1 . x > b . p0 . x && a . p0 . y < b . p1 . y && a . p1 . y > b . p0 . y ) ; }


Input: Finds the intersection between two rectangles . If the rectangles don t intersect then false is returned . [CODESPLIT] public static boolean intersection ( Rectangle2D_F64 a , Rectangle2D_F64 b , Rectangle2D_F64 result ) { if ( ! intersects ( a , b ) ) return false ; result . p0 . x = Math . max ( a . p0 . x , b . p0 . x ) ; result . p1 . x = Math . min ( a . p1 . x , b . p1 . x ) ; result . p0 . y = Math . max ( a . p0 . y , b . p0 . y ) ; result . p1 . y = Math . min ( a . p1 . y , b . p1 . y ) ; return true ; }


Input: Returns the area of the intersection of two rectangles . [CODESPLIT] public static double intersectionArea ( Rectangle2D_F64 a , Rectangle2D_F64 b ) { if ( ! intersects ( a , b ) ) return 0 ; double x0 = Math . max ( a . p0 . x , b . p0 . x ) ; double x1 = Math . min ( a . p1 . x , b . p1 . x ) ; double y0 = Math . max ( a . p0 . y , b . p0 . y ) ; double y1 = Math . min ( a . p1 . y , b . p1 . y ) ; return ( x1 - x0 ) * ( y1 - y0 ) ; }


Input: Determines the location ( s ) that a line and ellipse intersect . Returns the number of intersections found . NOTE : Due to floating point errors it s possible for a single solution to returned as two points . [CODESPLIT] public static int intersection ( LineGeneral2D_F64 line , EllipseRotated_F64 ellipse , Point2D_F64 intersection0 , Point2D_F64 intersection1 , double EPS ) { if ( EPS < 0 ) { EPS = GrlConstants . EPS ; } // First translate the line so that coordinate origin is the same as the ellipse double C = line . C + ( line . A * ellipse . center . x + line . B * ellipse . center . y ) ; // Now rotate the line double cphi = Math . cos ( ellipse . phi ) ; double sphi = Math . sin ( ellipse . phi ) ; double A = line . A * cphi + line . B * sphi ; double B = - line . A * sphi + line . B * cphi ; // Now solve for the intersections with the coordinate system centered and aligned to the ellipse // There are two different ways to solve for this.  Pick the axis with the largest slope // to avoid the pathological case double a2 = ellipse . a * ellipse . a ; double b2 = ellipse . b * ellipse . b ; double x0 , y0 ; double x1 , y1 ; int totalIntersections ; if ( Math . abs ( A ) > Math . abs ( B ) ) { double alpha = - C / A ; double beta = - B / A ; double aa = beta * beta / a2 + 1.0 / b2 ; double bb = 2.0 * alpha * beta / a2 ; double cc = alpha * alpha / a2 - 1.0 ; double inner = bb * bb - 4.0 * aa * cc ; if ( Math . abs ( inner / aa ) < EPS ) { // divide by aa for scale invariance totalIntersections = 1 ; inner = inner < 0 ? 0 : inner ; } else if ( inner < 0 ) { return 0 ; } else { totalIntersections = 2 ; } double right = Math . sqrt ( inner ) ; y0 = ( - bb + right ) / ( 2.0 * aa ) ; y1 = ( - bb - right ) / ( 2.0 * aa ) ; x0 = - ( C + B * y0 ) / A ; x1 = - ( C + B * y1 ) / A ; } else { double alpha = - C / B ; double beta = - A / B ; double aa = beta * beta / b2 + 1.0 / a2 ; double bb = 2.0 * alpha * beta / b2 ; double cc = alpha * alpha / b2 - 1.0 ; double inner = bb * bb - 4.0 * aa * cc ; if ( Math . abs ( inner / aa ) < EPS ) { // divide by aa for scale invariance totalIntersections = 1 ; inner = inner < 0 ? 0 : inner ; } else if ( inner < 0 ) { return 0 ; } else { totalIntersections = 2 ; } double right = Math . sqrt ( inner ) ; x0 = ( - bb + right ) / ( 2.0 * aa ) ; x1 = ( - bb - right ) / ( 2.0 * aa ) ; y0 = - ( A * x0 + C ) / B ; y1 = - ( A * x1 + C ) / B ; } // go back into world coordinate system intersection0 . x = x0 * cphi - y0 * sphi + ellipse . center . x ; intersection0 . y = x0 * sphi + y0 * cphi + ellipse . center . y ; intersection1 . x = x1 * cphi - y1 * sphi + ellipse . center . x ; intersection1 . y = x1 * sphi + y1 * cphi + ellipse . center . y ; return totalIntersections ; }


Input: Converts { @link georegression . struct . so . Rodrigues_F64 } into a rotation matrix . [CODESPLIT] public static DMatrixRMaj rodriguesToMatrix ( Rodrigues_F64 rodrigues , DMatrixRMaj R ) { return rodriguesToMatrix ( rodrigues . unitAxisRotation . x , rodrigues . unitAxisRotation . y , rodrigues . unitAxisRotation . z , rodrigues . theta , R ) ; }


Input: Converts axis angle ( { @link Rodrigues_F64 } ) into a rotation matrix with out needing to declare a storage variable . [CODESPLIT] public static DMatrixRMaj rodriguesToMatrix ( double axisX , double axisY , double axisZ , double theta , DMatrixRMaj R ) { R = checkDeclare3x3 ( R ) ; //noinspection UnnecessaryLocalVariable double x = axisX , y = axisY , z = axisZ ; double c = Math . cos ( theta ) ; double s = Math . sin ( theta ) ; double oc = 1.0 - c ; R . data [ 0 ] = c + x * x * oc ; R . data [ 1 ] = x * y * oc - z * s ; R . data [ 2 ] = x * z * oc + y * s ; R . data [ 3 ] = y * x * oc + z * s ; R . data [ 4 ] = c + y * y * oc ; R . data [ 5 ] = y * z * oc - x * s ; R . data [ 6 ] = z * x * oc - y * s ; R . data [ 7 ] = z * y * oc + x * s ; R . data [ 8 ] = c + z * z * oc ; return R ; }


Input: <p > Converts { @link georegression . struct . so . Rodrigues_F64 } into an euler rotation of different types< / p > [CODESPLIT] public static double [ ] rodriguesToEuler ( Rodrigues_F64 rodrigues , EulerType type , double [ ] euler ) { DMatrixRMaj R = rodriguesToMatrix ( rodrigues , null ) ; return matrixToEuler ( R , type , euler ) ; }


Input: <p > Converts { @link georegression . struct . so . Rodrigues_F64 } into a unit { @link georegression . struct . so . Quaternion_F64 } . < / p > [CODESPLIT] public static Quaternion_F64 rodriguesToQuaternion ( Rodrigues_F64 rodrigues , Quaternion_F64 quat ) { if ( quat == null ) quat = new Quaternion_F64 ( ) ; quat . w = Math . cos ( rodrigues . theta / 2.0 ) ; double s = Math . sin ( rodrigues . theta / 2.0 ) ; quat . x = rodrigues . unitAxisRotation . x * s ; quat . y = rodrigues . unitAxisRotation . y * s ; quat . z = rodrigues . unitAxisRotation . z * s ; return quat ; }


Input: Converts a unit { [CODESPLIT] public static Rodrigues_F64 quaternionToRodrigues ( Quaternion_F64 quat , Rodrigues_F64 rodrigues ) { if ( rodrigues == null ) rodrigues = new Rodrigues_F64 ( ) ; rodrigues . unitAxisRotation . set ( quat . x , quat . y , quat . z ) ; rodrigues . unitAxisRotation . normalize ( ) ; rodrigues . theta = 2.0 * Math . acos ( quat . w ) ; return rodrigues ; }


Input: <p > Converts a quaternion into an euler rotation of different types< / p > [CODESPLIT] public static double [ ] quaternionToEuler ( Quaternion_F64 q , EulerType type , double [ ] euler ) { DMatrixRMaj R = quaternionToMatrix ( q , null ) ; return matrixToEuler ( R , type , euler ) ; }


Input: <p > Converts a rotation matrix into an Euler angle of different types< / p > [CODESPLIT] public static double [ ] matrixToEuler ( DMatrixRMaj R , EulerType type , double [ ] euler ) { if ( euler == null ) euler = new double [ 3 ] ; switch ( type ) { case ZYX : TanSinTan ( - 2 , 1 , 3 , - 6 , 9 , 5 , - 7 , 4 , 8 , R , euler ) ; break ; case ZYZ : TanCosTan ( 8 , - 7 , 9 , 6 , 3 , 5 , - 7 , 4 , 8 , R , euler ) ; break ; case ZXY : TanSinTan ( 4 , 5 , - 6 , 3 , 9 , 1 , 8 , - 2 , 7 , R , euler ) ; break ; case ZXZ : TanCosTan ( 7 , 8 , 9 , 3 , - 6 , 1 , 8 , - 2 , 7 , R , euler ) ; break ; case YXZ : TanSinTan ( - 7 , 9 , 8 , - 2 , 5 , 1 , - 6 , 3 , 4 , R , euler ) ; break ; case YXY : TanCosTan ( 4 , - 6 , 5 , 2 , 8 , 1 , - 6 , 3 , 4 , R , euler ) ; break ; case YZX : TanSinTan ( 3 , 1 , - 2 , 8 , 5 , 9 , 4 , - 7 , 6 , R , euler ) ; break ; case YZY : TanCosTan ( 6 , 4 , 5 , 8 , - 2 , 9 , 4 , - 7 , 6 , R , euler ) ; break ; case XYZ : TanSinTan ( 8 , 9 , - 7 , 4 , 1 , 5 , 3 , - 6 , 2 , R , euler ) ; break ; case XYX : TanCosTan ( 2 , 3 , 1 , 4 , - 7 , 5 , 3 , - 6 , 2 , R , euler ) ; break ; case XZY : TanSinTan ( - 6 , 5 , 4 , - 7 , 1 , 9 , - 2 , 8 , 3 , R , euler ) ; break ; case XZX : TanCosTan ( 3 , - 2 , 1 , 7 , 4 , 9 , - 2 , 8 , 3 , R , euler ) ; break ; default : throw new IllegalArgumentException ( "Unknown rotation sequence" ) ; } return euler ; }


Input: If the index is negative it returns the negative of the value at - index . Starts at 0 [CODESPLIT] private static double get ( DMatrixRMaj M , int index ) { if ( index < 0 ) { return - M . data [ - index - 1 ] ; } else { return M . data [ index - 1 ] ; } }


Input: Extracts quaternions from the provided rotation matrix . [CODESPLIT] public static Quaternion_F64 matrixToQuaternion ( DMatrixRMaj R , Quaternion_F64 quat ) { if ( quat == null ) quat = new Quaternion_F64 ( ) ; // algorithm from: // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ // // Designed to minimize numerical error by not dividing by very small numbers double m00 = R . unsafe_get ( 0 , 0 ) ; double m01 = R . unsafe_get ( 0 , 1 ) ; double m02 = R . unsafe_get ( 0 , 2 ) ; double m10 = R . unsafe_get ( 1 , 0 ) ; double m11 = R . unsafe_get ( 1 , 1 ) ; double m12 = R . unsafe_get ( 1 , 2 ) ; double m20 = R . unsafe_get ( 2 , 0 ) ; double m21 = R . unsafe_get ( 2 , 1 ) ; double m22 = R . unsafe_get ( 2 , 2 ) ; double trace = m00 + m11 + m22 ; if ( trace > 0 ) { double S = Math . sqrt ( trace + 1.0 ) * 2 ; // S=4*qw quat . w = 0.25 * S ; quat . x = ( m21 - m12 ) / S ; quat . y = ( m02 - m20 ) / S ; quat . z = ( m10 - m01 ) / S ; } else if ( ( m00 > m11 ) & ( m00 > m22 ) ) { double S = Math . sqrt ( 1.0 + m00 - m11 - m22 ) * 2 ; // S=4*qx quat . w = ( m21 - m12 ) / S ; quat . x = 0.25 * S ; quat . y = ( m01 + m10 ) / S ; quat . z = ( m02 + m20 ) / S ; } else if ( m11 > m22 ) { double S = Math . sqrt ( 1.0 + m11 - m00 - m22 ) * 2 ; // S=4*qy quat . w = ( m02 - m20 ) / S ; quat . x = ( m01 + m10 ) / S ; quat . y = 0.25 * S ; quat . z = ( m12 + m21 ) / S ; } else { double S = Math . sqrt ( 1.0 + m22 - m00 - m11 ) * 2 ; // S=4*qz quat . w = ( m10 - m01 ) / S ; quat . x = ( m02 + m20 ) / S ; quat . y = ( m12 + m21 ) / S ; quat . z = 0.25 * S ; } return quat ; }


Input: Converts a rotation matrix into { @link georegression . struct . so . Rodrigues_F64 } . [CODESPLIT] public static Rodrigues_F64 matrixToRodrigues ( DMatrixRMaj R , Rodrigues_F64 rodrigues ) { if ( rodrigues == null ) { rodrigues = new Rodrigues_F64 ( ) ; } // parts of this are from wikipedia // http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29#Rotation_matrix_.E2.86.94_Euler_axis.2Fangle double diagSum = ( ( R . unsafe_get ( 0 , 0 ) + R . unsafe_get ( 1 , 1 ) + R . unsafe_get ( 2 , 2 ) ) - 1.0 ) / 2.0 ; double absDiagSum = Math . abs ( diagSum ) ; if ( absDiagSum <= 1.0 && 1.0 - absDiagSum > 10.0 * GrlConstants . EPS ) { // if numerically stable use a faster technique rodrigues . theta = Math . acos ( diagSum ) ; double bottom = 2.0 * Math . sin ( rodrigues . theta ) ; // in cases where bottom is close to zero that means theta is also close to zero and the vector // doesn't matter that much rodrigues . unitAxisRotation . x = ( R . unsafe_get ( 2 , 1 ) - R . unsafe_get ( 1 , 2 ) ) / bottom ; rodrigues . unitAxisRotation . y = ( R . unsafe_get ( 0 , 2 ) - R . unsafe_get ( 2 , 0 ) ) / bottom ; rodrigues . unitAxisRotation . z = ( R . unsafe_get ( 1 , 0 ) - R . unsafe_get ( 0 , 1 ) ) / bottom ; // in extreme underflow situations the result can be unnormalized rodrigues . unitAxisRotation . normalize ( ) ; // In theory this might be more stable // rotationAxis( R, rodrigues.unitAxisRotation); } else { // this handles the special case where the bottom is very very small or equal to zero if ( diagSum >= 1.0 ) rodrigues . theta = 0 ; else if ( diagSum <= - 1.0 ) rodrigues . theta = Math . PI ; else rodrigues . theta = Math . acos ( diagSum ) ; // compute the value of x,y,z up to a sign ambiguity rodrigues . unitAxisRotation . x = Math . sqrt ( ( R . get ( 0 , 0 ) + 1 ) / 2 ) ; rodrigues . unitAxisRotation . y = Math . sqrt ( ( R . get ( 1 , 1 ) + 1 ) / 2 ) ; rodrigues . unitAxisRotation . z = Math . sqrt ( ( R . get ( 2 , 2 ) + 1 ) / 2 ) ; double x = rodrigues . unitAxisRotation . x ; double y = rodrigues . unitAxisRotation . y ; double z = rodrigues . unitAxisRotation . z ; if ( Math . abs ( R . get ( 1 , 0 ) - 2 * x * y ) > GrlConstants . EPS ) { x *= - 1 ; } if ( Math . abs ( R . get ( 2 , 0 ) - 2 * x * z ) > GrlConstants . EPS ) { z *= - 1 ; } if ( Math . abs ( R . get ( 2 , 1 ) - 2 * z * y ) > GrlConstants . EPS ) { y *= - 1 ; x *= - 1 ; } rodrigues . unitAxisRotation . x = x ; rodrigues . unitAxisRotation . y = y ; rodrigues . unitAxisRotation . z = z ; } return rodrigues ; }


Input: Creates a rotation matrix about the x - axis . [CODESPLIT] public static DMatrixRMaj rotX ( double ang , DMatrixRMaj R ) { if ( R == null ) R = new DMatrixRMaj ( 3 , 3 ) ; setRotX ( ang , R ) ; return R ; }


Input: Sets the values in the specified matrix to a rotation matrix about the x - axis . [CODESPLIT] public static void setRotX ( double ang , DMatrixRMaj R ) { double c = Math . cos ( ang ) ; double s = Math . sin ( ang ) ; R . set ( 0 , 0 , 1 ) ; R . set ( 1 , 1 , c ) ; R . set ( 1 , 2 , - s ) ; R . set ( 2 , 1 , s ) ; R . set ( 2 , 2 , c ) ; }


Input: Creates a rotation matrix about the y - axis . [CODESPLIT] public static DMatrixRMaj rotY ( double ang , DMatrixRMaj R ) { R = checkDeclare3x3 ( R ) ; setRotY ( ang , R ) ; return R ; }


Input: Creates a rotation matrix about the z - axis . [CODESPLIT] public static DMatrixRMaj rotZ ( double ang , DMatrixRMaj R ) { R = checkDeclare3x3 ( R ) ; setRotZ ( ang , R ) ; return R ; }


Input: Sets the values in the specified matrix to a rotation matrix about the z - axis . [CODESPLIT] public static void setRotZ ( double ang , DMatrixRMaj r ) { double c = Math . cos ( ang ) ; double s = Math . sin ( ang ) ; r . set ( 0 , 0 , c ) ; r . set ( 0 , 1 , - s ) ; r . set ( 1 , 0 , s ) ; r . set ( 1 , 1 , c ) ; r . set ( 2 , 2 , 1 ) ; }


Input: Converts an Euler coordinate into a rotation matrix . Different type of Euler coordinates are accepted . [CODESPLIT] public static DMatrixRMaj eulerToMatrix ( EulerType type , double rotA , double rotB , double rotC , DMatrixRMaj R ) { R = checkDeclare3x3 ( R ) ; DMatrixRMaj R_a = rotationAboutAxis ( type . getAxisA ( ) , rotA , null ) ; DMatrixRMaj R_b = rotationAboutAxis ( type . getAxisB ( ) , rotB , null ) ; DMatrixRMaj R_c = rotationAboutAxis ( type . getAxisC ( ) , rotC , null ) ; DMatrixRMaj A = new DMatrixRMaj ( 3 , 3 ) ; CommonOps_DDRM . mult ( R_b , R_a , A ) ; CommonOps_DDRM . mult ( R_c , A , R ) ; return R ; }


Input: Creates a rotation matrix about the specified axis . [CODESPLIT] private static DMatrixRMaj rotationAboutAxis ( int axis , double angle , DMatrixRMaj R ) { switch ( axis ) { case 0 : return ConvertRotation3D_F64 . rotX ( angle , R ) ; case 1 : return ConvertRotation3D_F64 . rotY ( angle , R ) ; case 2 : return ConvertRotation3D_F64 . rotZ ( angle , R ) ; default : throw new IllegalArgumentException ( "Unknown which" ) ; } }


Input:
 Finds a rotation matrix which is the optimal approximation to an arbitrary 3 by 3 matrix . Optimality is specified by the equation below :

 min ||R - Q|| 2  F
 R
 where R is the rotation matrix and Q is the matrix being approximated .

 The technique used is based on SVD and is described in Appendix C of A Flexible New Technique for Camera Calibration Technical Report updated 2002 .

 Both origin and R can be the same instance .
 [CODESPLIT] public static DMatrixRMaj approximateRotationMatrix ( DMatrixRMaj orig , DMatrixRMaj R ) { R = checkDeclare3x3 ( R ) ; SingularValueDecomposition < DMatrixRMaj > svd = DecompositionFactory_DDRM . svd ( orig . numRows , orig . numCols , true , true , false ) ; if ( ! svd . decompose ( orig ) ) throw new RuntimeException ( "SVD Failed" ) ; CommonOps_DDRM . mult ( svd . getU ( null , false ) , svd . getV ( null , true ) , R ) ; // svd does not guarantee that U anv V have positive determinants. double det = CommonOps_DDRM . det ( R ) ; if ( det < 0 ) CommonOps_DDRM . scale ( - 1 , R ) ; return R ; }


Input: <p > Converts a unit quaternion into a rotation matrix . < / p > [CODESPLIT] public static DMatrixRMaj quaternionToMatrix ( Quaternion_F64 quat , DMatrixRMaj R ) { return quaternionToMatrix ( quat . w , quat . x , quat . y , quat . z , R ) ; }


Input: Sets the slope to the unit vector specified by the provided angle . [CODESPLIT] public void setAngle ( double angle ) { slope . set ( Math . cos ( angle ) , Math . sin ( angle ) ) ; }


Input: Returns a point along the line . See parametric equation in class description . [CODESPLIT] public Point2D_F64 getPointOnLine ( double t ) { return new Point2D_F64 ( slope . x * t + p . x , slope . y * t + p . y ) ; }


Input: Converts the { @link Se3_F64 } object into homogenous notation . <br > [CODESPLIT] public static DMatrixRMaj homogenous ( Se3_F64 transform , DMatrixRMaj H ) { if ( H == null ) { H = new DMatrixRMaj ( 4 , 4 ) ; } else { H . reshape ( 4 , 4 ) ; } CommonOps_DDRM . insert ( transform . R , H , 0 , 0 ) ; H . data [ 3 ] = transform . T . x ; H . data [ 7 ] = transform . T . y ; H . data [ 11 ] = transform . T . z ; H . data [ 12 ] = 0 ; H . data [ 13 ] = 0 ; H . data [ 14 ] = 0 ; H . data [ 15 ] = 1 ; return H ; }


Input: Converts the twist coordinate into homogenous format . <br > H = [ hat ( w ) v ; 0 0 ] [CODESPLIT] public static DMatrixRMaj homogenous ( TwistCoordinate_F64 twist , DMatrixRMaj H ) { if ( H == null ) { H = new DMatrixRMaj ( 4 , 4 ) ; } else { H . reshape ( 4 , 4 ) ; H . data [ 12 ] = 0 ; H . data [ 13 ] = 0 ; H . data [ 14 ] = 0 ; H . data [ 15 ] = 0 ; } H . data [ 0 ] = 0 ; H . data [ 1 ] = - twist . w . z ; H . data [ 2 ] = twist . w . y ; H . data [ 3 ] = twist . v . x ; H . data [ 4 ] = twist . w . z ; H . data [ 5 ] = 0 ; H . data [ 6 ] = - twist . w . x ; H . data [ 7 ] = twist . v . y ; H . data [ 8 ] = - twist . w . y ; H . data [ 9 ] = twist . w . x ; H . data [ 10 ] = 0 ; H . data [ 11 ] = twist . v . z ; return H ; }