$search
00001 #include "arena.h" 00002 #include "arenaelement.h" 00003 #include "arenaelementtype.h" 00004 #include "xmlloadingexception.h" 00005 00006 #include <QList> 00007 #include <QDebug> 00008 00009 #include <math.h> 00010 00011 ArenaElement::ArenaElement(const ArenaElementType * const type, int id) 00012 : m_type(type) 00013 , m_rotation(0) 00014 , m_instanceId(id) 00015 , m_itemMountPoint(-1) 00016 { 00017 } 00018 00019 bool ArenaElement::isWall() const 00020 { 00021 return m_type->type() == ArenaElementType::WallType; 00022 } 00023 00024 bool ArenaElement::isFloor() const 00025 { 00026 return m_type->type() == ArenaElementType::FloorType; 00027 } 00028 00029 bool ArenaElement::isMountableItem() const 00030 { 00031 return m_type->type() == ArenaElementType::MountableItemType; 00032 } 00033 00034 bool ArenaElement::isItem() const 00035 { 00036 return m_type->type() == ArenaElementType::ItemType; 00037 } 00038 00039 void ArenaElement::setPos(QPoint pos) 00040 { 00041 // Do not ignore if pos is same as before! We always have to emit posChanged(). 00042 //if (pos == m_pos) 00043 // return; 00044 m_pos = pos; 00045 emit posChanged(this, pos); 00046 emit modified(this); 00047 } 00048 00049 void ArenaElement::setItemOffset(const QPointF &offset) 00050 { 00051 m_itemOffset = offset; 00052 emit posChanged(this, m_pos); 00053 } 00054 00055 void ArenaElement::setRotation(int rotation) 00056 { 00057 // Do not ignore if rotation is same as before! We always have to emit rotationChanged(). 00058 //if (rotation == m_rotation) 00059 // return; 00060 // normalize also negative number (-2 % 3 == -2 but should be 1) 00061 // (-2 % 3 + 3) % 3 == (-2 + 3) % 3 == 1 00062 int normalizedRotation = (rotation % 360 + 360) % 360; 00063 m_rotation = normalizedRotation; 00064 emit rotationChanged(this, normalizedRotation); 00065 emit modified(this); 00066 } 00067 00068 void ArenaElement::setItemMountPoint(int mountPoint) 00069 { 00070 m_itemMountPoint = mountPoint; 00071 emit modified(this); 00072 } 00073 00074 void ArenaElement::load(const QDomElement& node) throw (XmlLoadingException) 00075 { 00076 if (!node.hasAttribute("x")) 00077 throw XmlLoadingException("An arena element is missing an x coordinate.", node); 00078 if (!node.hasAttribute("y")) 00079 throw XmlLoadingException("An arena element is missing a y coordinate.", node); 00080 00081 QPoint pos; 00082 pos.setX(node.attribute("x").toInt()); 00083 pos.setY(node.attribute("y").toInt()); 00084 setPos(pos); 00085 00086 if (node.hasAttribute("offset-x") && node.hasAttribute("offset-y")) 00087 { 00088 QString offsetX = node.attribute("offset-x"); 00089 QString offsetY = node.attribute("offset-y"); 00090 00091 QPointF offset = QPointF(offsetX.toFloat(), offsetY.toFloat()); 00092 setItemOffset(offset); 00093 } 00094 00095 if (node.hasAttribute("rotation")) 00096 { 00097 QString rotation = node.attribute("rotation"); 00098 setRotation(rotation.toInt()); 00099 } 00100 00101 if (node.hasAttribute("mount-point")) 00102 { 00103 QString mountPointIndex = node.attribute("mount-point"); 00104 setItemMountPoint(mountPointIndex.toInt()); 00105 } 00106 } 00107 00108 void ArenaElement::save(QXmlStreamWriter& writer) 00109 { 00110 writer.writeStartElement("element"); 00111 writer.writeAttribute("type", m_type->name()); 00112 writer.writeAttribute("rotation", QString::number(rotation())); 00113 writer.writeAttribute("x", QString::number(m_pos.x())); 00114 writer.writeAttribute("y", QString::number(m_pos.y())); 00115 00116 if (!m_itemOffset.isNull()) 00117 { 00118 writer.writeAttribute("offset-x", QString::number(m_itemOffset.x())); 00119 writer.writeAttribute("offset-y", QString::number(m_itemOffset.y())); 00120 } 00121 if (m_itemMountPoint != -1) 00122 writer.writeAttribute("mount-point", QString::number(m_itemMountPoint)); 00123 writer.writeEndElement(); 00124 } 00125 00126 void ArenaElement::saveWorld(QXmlStreamWriter& writer) 00127 { 00128 writer.writeStartElement("model:physical"); 00129 QString name; 00130 QTextStream(&name) << m_type->name() << "_" << m_instanceId; 00131 writer.writeAttribute("name", name); 00132 00133 ArenaElement *context = m_arena->contextElement(this); 00134 QList<ItemMountPoint> contextItemMountPoints; 00135 if (context) 00136 contextItemMountPoints = context->type()->itemMountPoints(); 00137 00138 // Use "corrected" mount point index 00139 int itemMountPoint = m_itemMountPoint; 00140 if (!isMountableItem() || !context) 00141 { 00142 itemMountPoint = -1; 00143 } 00144 else 00145 { 00146 // When there are possible mount points, use the first if none is assigned 00147 itemMountPoint = qMax(itemMountPoint, 0); 00148 // But make sure the index doesn't exceed the last mount point 00149 if (contextItemMountPoints.count() <= itemMountPoint) 00150 itemMountPoint = -1; 00151 } 00152 00153 qreal offsetX = 0; 00154 qreal offsetZ = 0; 00155 if (itemMountPoint >= 0) 00156 { 00157 Q_ASSERT(context); 00158 Q_ASSERT(contextItemMountPoints.count() > itemMountPoint); 00159 ItemMountPoint mountPoint = contextItemMountPoints[itemMountPoint]; 00160 offsetX = mountPoint.second.x() - 0.6; 00161 offsetZ = mountPoint.second.y(); 00162 } 00163 00164 QTransform trans; 00165 trans.rotate(-m_rotation); 00166 QPointF mappedOffset = trans.map(QPointF(offsetX, 0)); 00167 mappedOffset += m_itemOffset * 1.2; 00168 00169 QString xyz; 00170 // One unit is 1.2 meters, gazebo is set up to think in meters 00171 QTextStream(&xyz) << m_pos.x() * 1.2 + mappedOffset.x() << " " 00172 << m_pos.y() * 1.2 + mappedOffset.y() << " " << offsetZ; 00173 writer.writeTextElement("xyz", xyz); 00174 QString rpy; 00175 QTextStream(&rpy) << "0 0 " << -m_rotation; 00176 writer.writeTextElement("rpy", rpy); 00177 writer.writeTextElement("static", "true"); 00178 00179 writer.writeStartElement("body:trimesh"); 00180 writer.writeAttribute("name", name + "_body"); 00181 00182 writer.writeStartElement("geom:trimesh"); 00183 writer.writeAttribute("name", name + "_geom"); 00184 00185 writer.writeTextElement("mesh", m_type->mesh()); 00186 writer.writeTextElement("scale", "1.0 1.0 1.0"); 00188 writer.writeTextElement("genTexCoord", "true"); 00189 00190 writer.writeStartElement("visual"); 00191 writer.writeTextElement("scale", "1.0 1.0 1.0"); 00192 writer.writeTextElement("rpy", "0 0 0"); 00193 writer.writeTextElement("mesh", m_type->mesh()); 00194 //writer.writeTextElement("material", "Gazebo/WoodPallet"); 00195 // visual 00196 writer.writeEndElement(); 00197 00198 // geom:trimesh 00199 writer.writeEndElement(); 00200 00201 // body:trimesh 00202 writer.writeEndElement(); 00203 00204 // model:physical 00205 writer.writeEndElement(); 00206 } 00207 00208 void ArenaElement::saveWorldSdf(QXmlStreamWriter& writer) 00209 { 00210 writer.writeStartElement("model"); 00211 QString name; 00212 QTextStream(&name) << m_type->name() << "_" << m_instanceId; 00213 writer.writeAttribute("name", name); 00214 writer.writeAttribute("static", "true"); 00215 00216 ArenaElement *context = m_arena->contextElement(this); 00217 QList<ItemMountPoint> contextItemMountPoints; 00218 if (context) 00219 contextItemMountPoints = context->type()->itemMountPoints(); 00220 00221 // Use "corrected" mount point index 00222 int itemMountPoint = m_itemMountPoint; 00223 if (!isMountableItem() || !context) 00224 { 00225 itemMountPoint = -1; 00226 } 00227 else 00228 { 00229 // When there are possible mount points, use the first if none is assigned 00230 itemMountPoint = qMax(itemMountPoint, 0); 00231 // But make sure the index doesn't exceed the last mount point 00232 if (contextItemMountPoints.count() <= itemMountPoint) 00233 itemMountPoint = -1; 00234 } 00235 00236 qreal offsetX = 0; 00237 qreal offsetZ = 0; 00238 if (itemMountPoint >= 0) 00239 { 00240 Q_ASSERT(context); 00241 Q_ASSERT(contextItemMountPoints.count() > itemMountPoint); 00242 ItemMountPoint mountPoint = contextItemMountPoints[itemMountPoint]; 00243 offsetX = mountPoint.second.x() - 0.6; 00244 offsetZ = mountPoint.second.y(); 00245 } 00246 00247 QTransform trans; 00248 trans.rotate(-m_rotation); 00249 QPointF mappedOffset = trans.map(QPointF(offsetX, 0)); 00250 mappedOffset += m_itemOffset * 1.2; 00251 00252 QString xyz; 00253 // One unit is 1.2 meters, gazebo is set up to think in meters 00254 QTextStream(&xyz) << m_pos.x() * 1.2 + mappedOffset.x() << " " 00255 << m_pos.y() * 1.2 + mappedOffset.y() << " " << offsetZ; 00256 00257 QString rpy; 00258 QTextStream(&rpy) << "0 0 " << -(m_rotation/180.0)*M_PI; 00259 //writer.writeTextElement("rpy", rpy); 00260 00261 writer.writeStartElement("link"); 00262 writer.writeAttribute("name",name+"_link"); 00263 00264 writer.writeStartElement("origin"); 00265 writer.writeAttribute("pose",xyz + " " + rpy); 00266 writer.writeEndElement(); 00267 00268 writer.writeStartElement("collision"); 00269 writer.writeAttribute("name",name+"_collision"); 00270 00271 writer.writeStartElement("geometry"); 00272 00273 writer.writeStartElement("mesh"); 00274 writer.writeAttribute("filename",m_type->mesh()); 00275 writer.writeAttribute("scale","1 1 1"); 00276 writer.writeEndElement(); 00277 00278 writer.writeEndElement(); 00279 00280 writer.writeEndElement(); 00281 00282 writer.writeStartElement("visual"); 00283 writer.writeAttribute("name",name+"_visual"); 00284 writer.writeAttribute("cast_shadows","false"); 00285 00286 writer.writeStartElement("geometry"); 00287 00288 writer.writeStartElement("mesh"); 00289 writer.writeAttribute("filename",m_type->mesh()); 00290 writer.writeAttribute("scale","1 1 1"); 00291 writer.writeEndElement(); 00292 00293 writer.writeEndElement(); 00294 00295 writer.writeEndElement(); 00296 00297 writer.writeEndElement(); 00298 00299 writer.writeEndElement(); 00300 00301 } 00302 00303 00304 00305 00306 00307 00308 00309 00310