FrameTransformTree.java
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 Google Inc.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
00005  * use this file except in compliance with the License. You may obtain a copy of
00006  * the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00013  * License for the specific language governing permissions and limitations under
00014  * the License.
00015  */
00016 
00017 package org.ros.rosjava_geometry;
00018 
00019 import com.google.common.annotations.VisibleForTesting;
00020 import com.google.common.base.Preconditions;
00021 import com.google.common.collect.Maps;
00022 
00023 import geometry_msgs.TransformStamped;
00024 import org.ros.concurrent.CircularBlockingDeque;
00025 import org.ros.message.Time;
00026 import java.util.Map;
00027 
00037 public class FrameTransformTree {
00038 
00039   private static final int TRANSFORM_QUEUE_CAPACITY = 16;
00040 
00041   private final Object mutex;
00042 
00048   private final Map<FrameName, CircularBlockingDeque<LazyFrameTransform>> transforms;
00049 
00050   public FrameTransformTree() {
00051     mutex = new Object();
00052     transforms = Maps.newConcurrentMap();
00053   }
00054 
00066   public void update(geometry_msgs.TransformStamped transformStamped) {
00067     Preconditions.checkNotNull(transformStamped);
00068     FrameName transformName = FrameName.of(transformStamped.getChildFrameId());
00069     LazyFrameTransform lazyFrameTransform = new LazyFrameTransform(transformStamped);
00070     add(transformName, lazyFrameTransform);
00071   }
00072 
00073   @VisibleForTesting
00074   void update(FrameTransform frameTransform) {
00075     Preconditions.checkNotNull(frameTransform);
00076     FrameName source = frameTransform.getSourceFrame();
00077     LazyFrameTransform lazyFrameTransform = new LazyFrameTransform(frameTransform);
00078     add(source, lazyFrameTransform);
00079   }
00080 
00081   private void add(FrameName source, LazyFrameTransform lazyFrameTransform) {
00082     if (!transforms.containsKey(source)) {
00083       transforms.put(source, new CircularBlockingDeque<LazyFrameTransform>(
00084           TRANSFORM_QUEUE_CAPACITY));
00085     }
00086     synchronized (mutex) {
00087       transforms.get(source).addFirst(lazyFrameTransform);
00088     }
00089   }
00090 
00099   public FrameTransform lookUp(FrameName source) {
00100     Preconditions.checkNotNull(source);
00101     return getLatest(source);
00102   }
00103 
00104   private FrameTransform getLatest(FrameName source) {
00105     CircularBlockingDeque<LazyFrameTransform> deque = transforms.get(source);
00106     if (deque == null) {
00107       return null;
00108     }
00109     LazyFrameTransform lazyFrameTransform = deque.peekFirst();
00110     if (lazyFrameTransform == null) {
00111       return null;
00112     }
00113     return lazyFrameTransform.get();
00114   }
00115 
00119   public FrameTransform get(String source) {
00120     Preconditions.checkNotNull(source);
00121     return lookUp(FrameName.of(source));
00122   }
00123 
00136   public FrameTransform lookUp(FrameName source, Time time) {
00137     Preconditions.checkNotNull(source);
00138     Preconditions.checkNotNull(time);
00139     return get(source, time);
00140   }
00141 
00142   // TODO(damonkohler): Use an efficient search.
00143   private FrameTransform get(FrameName source, Time time) {
00144     CircularBlockingDeque<LazyFrameTransform> deque = transforms.get(source);
00145     if (deque == null) {
00146       return null;
00147     }
00148     LazyFrameTransform result = null;
00149     synchronized (mutex) {
00150       long offset = 0;
00151       for (LazyFrameTransform lazyFrameTransform : deque) {
00152         if (result == null) {
00153           result = lazyFrameTransform;
00154           offset = Math.abs(time.subtract(result.get().getTime()).totalNsecs());
00155           continue;
00156         }
00157         long newOffset = Math.abs(time.subtract(lazyFrameTransform.get().getTime()).totalNsecs());
00158         if (newOffset < offset) {
00159           result = lazyFrameTransform;
00160           offset = newOffset;
00161         }
00162       }
00163     }
00164     if (result == null) {
00165       return null;
00166     }
00167     return result.get();
00168   }
00169 
00173   public FrameTransform get(String source, Time time) {
00174     Preconditions.checkNotNull(source);
00175     return lookUp(FrameName.of(source), time);
00176   }
00177 
00182   public FrameTransform transform(FrameName source, FrameName target) {
00183     Preconditions.checkNotNull(source);
00184     Preconditions.checkNotNull(target);
00185     if (source.equals(target)) {
00186       return new FrameTransform(Transform.identity(), source, target, null);
00187     }
00188     FrameTransform sourceToRoot = transformToRoot(source);
00189     FrameTransform targetToRoot = transformToRoot(target);
00190     if (sourceToRoot == null && targetToRoot == null) {
00191       return null;
00192     }
00193     if (sourceToRoot == null) {
00194       if (targetToRoot.getTargetFrame().equals(source)) {
00195         // resolvedSource is root.
00196         return targetToRoot.invert();
00197       } else {
00198         return null;
00199       }
00200     }
00201     if (targetToRoot == null) {
00202       if (sourceToRoot.getTargetFrame().equals(target)) {
00203         // resolvedTarget is root.
00204         return sourceToRoot;
00205       } else {
00206         return null;
00207       }
00208     }
00209     if (sourceToRoot.getTargetFrame().equals(targetToRoot.getTargetFrame())) {
00210       // Neither resolvedSource nor resolvedTarget is root and both share the
00211       // same root.
00212       Transform transform =
00213           targetToRoot.getTransform().invert().multiply(sourceToRoot.getTransform());
00214       return new FrameTransform(transform, source, target, sourceToRoot.getTime());
00215     }
00216     // No known transform.
00217     return null;
00218   }
00219 
00223   public FrameTransform transform(String source, String target) {
00224     Preconditions.checkNotNull(source);
00225     Preconditions.checkNotNull(target);
00226     return transform(FrameName.of(source), FrameName.of(target));
00227   }
00228 
00234   @VisibleForTesting
00235   FrameTransform transformToRoot(FrameName source) {
00236     FrameTransform result = getLatest(source);
00237     if (result == null) {
00238       return null;
00239     }
00240     while (true) {
00241       FrameTransform resultToParent = lookUp(result.getTargetFrame(), result.getTime());
00242       if (resultToParent == null) {
00243         return result;
00244       }
00245       // Now resultToParent.getSourceFrame() == result.getTargetFrame()
00246       Transform transform = resultToParent.getTransform().multiply(result.getTransform());
00247       FrameName target = resultToParent.getTargetFrame();
00248       result = new FrameTransform(transform, source, target, result.getTime());
00249     }
00250   }
00251 }


rosjava_core
Author(s):
autogenerated on Wed Aug 26 2015 16:06:49