Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
00196 return targetToRoot.invert();
00197 } else {
00198 return null;
00199 }
00200 }
00201 if (targetToRoot == null) {
00202 if (sourceToRoot.getTargetFrame().equals(target)) {
00203
00204 return sourceToRoot;
00205 } else {
00206 return null;
00207 }
00208 }
00209 if (sourceToRoot.getTargetFrame().equals(targetToRoot.getTargetFrame())) {
00210
00211
00212 Transform transform =
00213 targetToRoot.getTransform().invert().multiply(sourceToRoot.getTransform());
00214 return new FrameTransform(transform, source, target, sourceToRoot.getTime());
00215 }
00216
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
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 }