提交 55affcf6 编写于 作者: 丁劲犇's avatar 丁劲犇 😸

Add a multiline graphics item, based on QGraphicsPathItem

Multiline can hold several lines in one top-level item. now, point, line, multiline, polygon, these geo types can hold WKT style geo elements in future.
上级 e9fcd546
#include "geographicsmultilineitem.h"
#include "../qtviewer_planetosm/osmtiles/viewer_interface.h"
#include <assert.h>
#include <QGraphicsSceneMouseEvent>
#include <math.h>
#include "geographicsscene.h"
#include "qtvplugin_geomarker.h"
namespace QTVP_GEOMARKER{
geoGraphicsMultilineItem::geoGraphicsMultilineItem(
QString name,
QTVOSM::viewer_interface * pVi,const QPolygonF & lla_polygon)
:QGraphicsPathItem(0)
,geoItemBase(name,QTVP_GEOMARKER::ITEAMTYPE_MULTILINE,pVi)
{
assert(vi()!=0);
m_llap = lla_polygon;
unwarrp();
QPainterPath wp;
int c = 0;
foreach (const QPointF & pt, m_llap)
{
double px,py;
vi()->CV_LLA2World(pt.y(),pt.x(),&px,&py);
if (c==0)
wp.moveTo(QPointF(px,py));
else
wp.lineTo(QPointF(px,py));
++c;
}
setPath(wp);
}
void geoGraphicsMultilineItem::unwarrp()
{
int sz = m_llap.size();
if (sz<2)
return;
for (int i=1;i<sz;++i)
{
qreal m_lon1 = m_llap[i-1].x();
qreal m_lon2 = m_llap[i].x();
while (m_lon2 - m_lon1 < -180)
m_lon2 += 360;
while (m_lon2 - m_lon1 > 180)
m_lon2 -= 360;
m_llap[i].setX(m_lon2);
}
}
void geoGraphicsMultilineItem::adjust_coords(int nNewLevel)
{
if (vi() && nNewLevel != level())
{
/** Since the map is zooming from level() to current level,
* the map size zoom ratio can be calculated using pow below.
* We can get new coord for current zoom level by multiplicative.
*/
double ratio = pow(2.0,(nNewLevel - level()));
QPainterPath p = this->path();
int sz = p.elementCount();
for (int i=0;i<sz;++i)
{
QPainterPath::Element pt = p.elementAt(i);
pt.x *= ratio;
pt.y *= ratio;
p.setElementPositionAt(i,pt.x,pt.y);
}
this->setPath(p);
}
}
void geoGraphicsMultilineItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
QGraphicsPathItem::mousePressEvent(event);
bool bshow = this->props_visible();
this->show_props(!bshow);
//post enent
QMap<QString, QVariant > map_evt;
geoGraphicsScene * pscene = dynamic_cast<geoGraphicsScene *>(this->scene());
if (pscene)
{
QObject * pPlg = pscene->parent();
if (pPlg)
{
qtvplugin_geomarker * pMarker = dynamic_cast<qtvplugin_geomarker *>(pPlg) ;
if (pMarker)
{
map_evt["source"] = pMarker->get_name();
map_evt["destin"] = "ALL";
if (event->buttons() & Qt::LeftButton)
map_evt["name"] = "ITEM_LBUTTON_CLICKED";
else if (event->buttons() & Qt::RightButton)
map_evt["name"] = "ITEM_RBUTTON_CLICKED";
else if (event->buttons() & Qt::MidButton)
map_evt["name"] = "ITEM_MBUTTON_CLICKED";
else
map_evt["name"] = "ITEM_BUTTON_CLICKED";
map_evt["id"] = this->item_name();
vi()->post_event(map_evt);
}
}
}
}
void geoGraphicsMultilineItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)
{
QGraphicsPathItem::mouseDoubleClickEvent(event);
//post enent
QMap<QString, QVariant > map_evt;
geoGraphicsScene * pscene = dynamic_cast<geoGraphicsScene *>(this->scene());
if (pscene)
{
QObject * pPlg = pscene->parent();
if (pPlg)
{
qtvplugin_geomarker * pMarker = dynamic_cast<qtvplugin_geomarker *>(pPlg) ;
if (pMarker)
{
map_evt["source"] = pMarker->get_name();
map_evt["destin"] = "ALL";
if (event->buttons() & Qt::LeftButton)
map_evt["name"] = "ITEM_LBUTTON_DBLCLICKED";
else if (event->buttons() & Qt::RightButton)
map_evt["name"] = "ITEM_RBUTTON_DBLCLICKED";
else if (event->buttons() & Qt::MidButton)
map_evt["name"] = "ITEM_MBUTTON_DBLCLICKED";
else
map_evt["name"] = "ITEM_BUTTON_DBLCLICKED";
map_evt["id"] = this->item_name();
vi()->post_event(map_evt);
}
}
}
}
QPointF geoGraphicsMultilineItem::label_pos()
{
QPainterPath p = this->path();
int sz = p.elementCount();
double x = 0, y = 0;
for (int i=0;i<sz;++i)
{
x += p.elementAt(i).x;
y += p.elementAt(i).y;
}
if (sz)
{
x /= sz;
y /= sz;
}
return QPointF(x,y);
}
void geoGraphicsMultilineItem::setGeo(const QPolygonF & lla_polygon)
{
m_llap = lla_polygon;
unwarrp();
QPainterPath wp;
int c = 0;
foreach (const QPointF & pt, m_llap)
{
double px,py;
vi()->CV_LLA2World(pt.y(),pt.x(),&px,&py);
if (c==0)
wp.moveTo(QPointF(px,py));
else
wp.lineTo(QPointF(px,py));
++c;
}
setPath(wp);
adjustLabelPos();
}
}
#ifndef GEOGRAPHICSMULTILINEITEM_H
#define GEOGRAPHICSMULTILINEITEM_H
#include <QGraphicsPathItem>
#include <QPolygonF>
#include "geoitembase.h"
namespace QTVP_GEOMARKER{
class geoGraphicsMultilineItem : public QGraphicsPathItem, public geoItemBase
{
protected:
QPolygonF m_llap;
void unwarrp();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent * event);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event);
public:
explicit geoGraphicsMultilineItem(QString name,QTVOSM::viewer_interface * pVi,
const QPolygonF & lla_polygon
);
public:
QPolygonF llas() const {return m_llap;}
void setGeo(const QPolygonF & lla_polygon);
void adjust_coords(int nNewLevel);
QPointF label_pos();
QPointF center_pos(){
qreal x = path().elementAt(0).x;
qreal y = path().elementAt(0).y;
return QPointF(x,y);
}
};
}
#endif // geoGraphicsMultilineItem_H
......@@ -18,7 +18,8 @@ namespace QTVP_GEOMARKER{
ITEAMTYPE_RECT_POINT = 2,
ITEAMTYPE_LINE = 3,
ITEAMTYPE_POLYGON = 4,
ITEAMTYPE_PIXMAP = 5
ITEAMTYPE_PIXMAP = 5,
ITEAMTYPE_MULTILINE = 6
};
inline const QString & item_name_by_enum(geo_item_type tp)
{
......@@ -29,6 +30,7 @@ namespace QTVP_GEOMARKER{
"LINE",
"POLYGON",
"ICON",
"MULTILINE",
"ERROR"
};
return names[(int)tp];
......
......@@ -16,6 +16,7 @@
#include "geographicslineitem.h"
#include "geographicspolygonitem.h"
#include "geographicspixmapitem.h"
#include "geographicsmultilineitem.h"
QMutex mutex_instances;
QMap<viewer_interface *, qtvplugin_geomarker * > map_instances;
QMap<QString, int > count_instances;
......@@ -528,7 +529,7 @@ QTVP_GEOMARKER::geoItemBase * qtvplugin_geomarker::update_line(const QString &
}
QTVP_GEOMARKER::geoItemBase * qtvplugin_geomarker::update_polygon (const QString & name,const QPolygonF latlons, QPen pen, QBrush brush)
QTVP_GEOMARKER::geoItemBase * qtvplugin_geomarker::update_polygon (const QString & name,const QPolygonF latlons, QPen pen, QBrush brush, bool tp)
{
QTVP_GEOMARKER::geoItemBase * res = 0;
//Get raw Item by name
......@@ -541,36 +542,72 @@ QTVP_GEOMARKER::geoItemBase * qtvplugin_geomarker::update_polygon (const QStr
propNames = base->prop_names();
propValues = base->prop_values();
}
//type convertion to T
QTVP_GEOMARKER::geoGraphicsPolygonItem * pitem = base?dynamic_cast<QTVP_GEOMARKER::geoGraphicsPolygonItem *>(base):0;
if (!pitem)
pitem = new QTVP_GEOMARKER::geoGraphicsPolygonItem(name,
this->m_pVi,
latlons);
pitem->setPen(pen);
pitem->setBrush(brush);
if (base == pitem)
{
pitem->setGeo(latlons);
res = pitem;
}
else if (false==this->m_pScene->addItem(pitem,0))
if (tp==false)
{
if (base != pitem)
delete pitem;
//type convertion to T
QTVP_GEOMARKER::geoGraphicsPolygonItem * pitem = base?dynamic_cast<QTVP_GEOMARKER::geoGraphicsPolygonItem *>(base):0;
if (!pitem)
pitem = new QTVP_GEOMARKER::geoGraphicsPolygonItem(name,
this->m_pVi,
latlons);
pitem->setPen(pen);
pitem->setBrush(brush);
if (base == pitem)
{
pitem->setGeo(latlons);
res = pitem;
}
else if (false==this->m_pScene->addItem(pitem,0))
{
if (base != pitem)
delete pitem;
}
else
{
int cs = propNames.size();
for (int i=0;i<cs && base != pitem;++i)
{
pitem->set_prop_data(propNames.first(), propValues.first());
propNames.pop_front();
propValues.pop_front();
}
res = pitem;
}
}
else
{
int cs = propNames.size();
for (int i=0;i<cs && base != pitem;++i)
//type convertion to T
QTVP_GEOMARKER::geoGraphicsMultilineItem * pitem = base?dynamic_cast<QTVP_GEOMARKER::geoGraphicsMultilineItem *>(base):0;
if (!pitem)
pitem = new QTVP_GEOMARKER::geoGraphicsMultilineItem(name,
this->m_pVi,
latlons);
pitem->setPen(pen);
//pitem->setBrush(QBrush(Qt::NoBrush));
if (base == pitem)
{
pitem->set_prop_data(propNames.first(), propValues.first());
propNames.pop_front();
propValues.pop_front();
pitem->setGeo(latlons);
res = pitem;
}
else if (false==this->m_pScene->addItem(pitem,0))
{
if (base != pitem)
delete pitem;
}
else
{
int cs = propNames.size();
for (int i=0;i<cs && base != pitem;++i)
{
pitem->set_prop_data(propNames.first(), propValues.first());
propNames.pop_front();
propValues.pop_front();
}
res = pitem;
}
res = pitem;
}
return res;
}
QTVP_GEOMARKER::geoItemBase * qtvplugin_geomarker::update_icon(const QString & name,double lat, double lon,qreal scale, qreal rotate,int smooth, QString id)
......
......@@ -126,7 +126,7 @@ private:
template <class T>
QTVP_GEOMARKER::geoItemBase * update_point (const QString & name,double lat, double lon, int width, int height, QPen pen, QBrush brush);
QTVP_GEOMARKER::geoItemBase * update_line (const QString & name,double lat1, double lon1,double lat2, double lon2, QPen pen);
QTVP_GEOMARKER::geoItemBase * update_polygon (const QString & name,const QPolygonF latlons, QPen pen, QBrush brush);
QTVP_GEOMARKER::geoItemBase * update_polygon (const QString & name,const QPolygonF latlons, QPen pen, QBrush brush, bool tp);
QTVP_GEOMARKER::geoItemBase * update_icon (const QString & name,double lat, double lon,qreal scale, qreal rotate,int smooth, QString id);
//update method for XML
bool xml_update_mark (tag_xml_mark & mark);
......
......@@ -24,7 +24,8 @@ SOURCES += \
qtvplugin_geomarker_func.cpp \
qtvplugin_geomarker_xml.cpp \
geographicspixmapitem.cpp \
dialogselecticon.cpp
dialogselecticon.cpp \
geographicsmultilineitem.cpp
HEADERS +=\
../qtviewer_planetosm/osmtiles/layer_interface.h \
......@@ -37,7 +38,8 @@ HEADERS +=\
geographicslineitem.h \
geographicspolygonitem.h \
geographicspixmapitem.h \
dialogselecticon.h
dialogselecticon.h \
geographicsmultilineitem.h
FORMS += \
qtvplugin_geomarker.ui \
......
......@@ -417,6 +417,13 @@
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
<widget class="QCheckBox" name="checkBox_close">
<property name="text">
<string>Multiline(Not close)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
......
......@@ -4,6 +4,7 @@
#include "geographicslineitem.h"
#include "geographicspolygonitem.h"
#include "geographicsrectitem.h"
#include "geographicsmultilineitem.h"
#include <QDebug>
#include <QMap>
/**
......@@ -489,6 +490,20 @@ QMap<QString, QVariant> qtvplugin_geomarker::func_update_polygon (const QMap<QS
res["error"] = tr("name could not be empty.");
return std::move(res);
}
int type = 4;//polygon
if (paras.contains("type")==true)
{
type = paras["type"].toInt();
}
if (name.size()==0)
{
res["error"] = tr("name could not be empty.");
return std::move(res);
}
QTVP_GEOMARKER::geoItemBase * base = m_pScene->geoitem_by_name(name);
QPen pen(Qt::SolidLine);
QBrush brush(QColor(255,255,255,128));
......@@ -496,7 +511,7 @@ QMap<QString, QVariant> qtvplugin_geomarker::func_update_polygon (const QMap<QS
//if the mark is already exist, we will get its orgional style as default .
if (base)
{
if (base->item_type()==QTVP_GEOMARKER::ITEAMTYPE_POLYGON)
if (base->item_type()==QTVP_GEOMARKER::ITEAMTYPE_POLYGON && type !=6)
{
QTVP_GEOMARKER::geoGraphicsPolygonItem * it = dynamic_cast<QTVP_GEOMARKER::geoGraphicsPolygonItem * >(base);
if (it)
......@@ -505,6 +520,12 @@ QMap<QString, QVariant> qtvplugin_geomarker::func_update_polygon (const QMap<QS
brush = it->brush();
}
}
else if (base->item_type()==QTVP_GEOMARKER::ITEAMTYPE_MULTILINE && type !=4)
{
QTVP_GEOMARKER::geoGraphicsMultilineItem * it = dynamic_cast<QTVP_GEOMARKER::geoGraphicsMultilineItem * >(base);
if (it)
pen = it->pen();
}
}
......@@ -592,8 +613,8 @@ QMap<QString, QVariant> qtvplugin_geomarker::func_update_polygon (const QMap<QS
strKeyLon = QString("lon%1").arg(ct);
}
//update using same function in UI
if (pl.size()>2)
newitem = update_polygon(name,pl,pen,brush);
if (pl.size()>2 || (type!=4 && pl.size()>1))
newitem = update_polygon(name,pl,pen,brush,type==6?true:false);
else
res["error"] = tr("polygon must contain at least 3 points,lat0,lat1,lat2 and lon0,lon1, lon2.");
......@@ -659,13 +680,13 @@ QMap<QString, QVariant> qtvplugin_geomarker::func_update_props(const QMap<QStrin
if (key!="name" && key!="function")
base->set_prop_data(key,paras[key]);
}
scheduleRefreshMarks();
scheduleUpdateMap();
if (base->props_visible())
{
base->show_props(false);
base->show_props(true);
}
scheduleRefreshMarks();
scheduleUpdateMap();
}
else
res["error"] = tr("name does not exist in scene.");
......@@ -804,13 +825,13 @@ QMap<QString, QVariant> qtvplugin_geomarker::func_delete_props (const QMap<QSt
if (needUpdate)
{
scheduleRefreshMarks();
scheduleUpdateMap();
if (base->props_visible())
{
base->show_props(false);
base->show_props(true);
}
scheduleRefreshMarks();
scheduleUpdateMap();
}
return std::move(res);
}
......@@ -958,6 +979,28 @@ QMap<QString, QVariant> qtvplugin_geomarker::func_mark (const QMap<QString,
}
}
break;
case QTVP_GEOMARKER::ITEAMTYPE_MULTILINE:
{
QTVP_GEOMARKER::geoGraphicsMultilineItem * pU = dynamic_cast<QTVP_GEOMARKER::geoGraphicsMultilineItem *>(item);
if (pU)
{
QPolygonF pl = pU->llas();
int nPl = pl.size();
for (int in = 0;in < nPl; ++in)
{
QString keyLat = QString("lat%1").arg(in);
QString keyLon = QString("lon%1").arg(in);
res[keyLat] = QString("%1").arg(pl[in].y(),0,'f',7);
res[keyLon] = QString("%1").arg(pl[in].x(),0,'f',7);
}
res["color_pen"] = color2string(pU->pen().color());
res["style_pen"] = QString("%1").arg(int(pU->pen().style()));
res["width_pen"] = QString("%1").arg(int(pU->pen().width()));
res["color_brush"] = color2string(pU->brush().color());
res["style_brush"] = QString("%1").arg(int(pU->brush().style()));
}
}
break;
default:
break;
}
......
......@@ -12,6 +12,7 @@
#include "geographicsrectitem.h"
#include "geographicslineitem.h"
#include "geographicspolygonitem.h"
#include "geographicsmultilineitem.h"
#include "dialogselecticon.h"
void qtvplugin_geomarker::timerEvent(QTimerEvent * e)
......@@ -23,7 +24,7 @@ void qtvplugin_geomarker::timerEvent(QTimerEvent * e)
if (m_items_to_insert.empty()==true)
{
m_items_to_insert = m_pScene->geo_item_names();
m_pGeoItemModel->clear();
m_pGeoItemModel->removeRows(0,m_pGeoItemModel->rowCount());
}
//refersh
int ct = 0;
......@@ -176,6 +177,7 @@ void qtvplugin_geomarker::ini_save()
settings.setValue("ui/lineEdit_icon_lon",ui->lineEdit_icon_lon->text());
settings.setValue("ui/lineEdit_icon_rotate",ui->lineEdit_icon_rotate->text());
settings.setValue("ui/lineEdit_icon_scale",ui->lineEdit_icon_scale->text());
settings.setValue("ui/checkBox_close",ui->checkBox_close->isChecked()?-1:0);
}
void qtvplugin_geomarker::ini_load()
......@@ -268,6 +270,9 @@ void qtvplugin_geomarker::ini_load()
QString lineEdit_icon_rotate = settings.value("ui/lineEdit_icon_rotate","1.0").toString();
ui->lineEdit_icon_rotate->setText(lineEdit_icon_rotate);
int checkBox_close = settings.value("ui/checkBox_close",0).toInt();
ui->checkBox_close->setChecked(checkBox_close?true:false);
}
void qtvplugin_geomarker::on_pushButton_update_clicked()
{
......@@ -367,7 +372,7 @@ void qtvplugin_geomarker::on_pushButton_update_clicked()
latlons.push_back(ll);
}
if (latlons.size())
newitem = update_polygon(name,latlons,pen,brush);
newitem = update_polygon(name,latlons,pen,brush,ui->checkBox_close->isChecked()?true:false);
}
else if (ui->radioButton_tool_icons->isChecked())
......@@ -567,6 +572,7 @@ void qtvplugin_geomarker::refreshItemUI(QString markname)
strPlainText += QString("%1,%2;\n").arg(p.y(),0,'f',7).arg(p.x(),0,'f',7);
ui->plainTextEdit_corners->setPlainText(strPlainText);
ui->radioButton_tool_polygon->setChecked(true);
ui->checkBox_close->setChecked(false);
}
break;
case QTVP_GEOMARKER::ITEAMTYPE_PIXMAP:
......@@ -583,6 +589,23 @@ void qtvplugin_geomarker::refreshItemUI(QString markname)
ui->comboBox_icons->setCurrentText(nameicon);
}
break;
case QTVP_GEOMARKER::ITEAMTYPE_MULTILINE:
{
QTVP_GEOMARKER::geoGraphicsMultilineItem * pitem = dynamic_cast<QTVP_GEOMARKER::geoGraphicsMultilineItem *>(item);
if (!pitem)
break;
pen = pitem->pen();
brush = pitem->brush();
QPolygonF pol = pitem->llas();
QString strPlainText;
foreach (QPointF p, pol)
strPlainText += QString("%1,%2;\n").arg(p.y(),0,'f',7).arg(p.x(),0,'f',7);
ui->plainTextEdit_corners->setPlainText(strPlainText);
ui->radioButton_tool_polygon->setChecked(true);
ui->checkBox_close->setChecked(true);
}
break;
default:
break;
......
......@@ -6,6 +6,7 @@
#include "geographicslineitem.h"
#include "geographicspolygonitem.h"
#include "geographicsrectitem.h"
#include "geographicsmultilineitem.h"
#include <QDebug>
#include <QXmlStreamAttributes>
#include <QMap>
......@@ -145,6 +146,31 @@ bool qtvplugin_geomarker::xml_save(QString xml)
stream.writeTextElement("scale",QString("%1").arg(pU->scale()));
stream.writeTextElement("rotate",QString("%1").arg(pU->rotation()));
stream.writeTextElement("smooth",QString("%1").arg(pU->transformationMode()==Qt::SmoothTransformation?1:0));
}
}
break;
case QTVP_GEOMARKER::ITEAMTYPE_MULTILINE:
{
QTVP_GEOMARKER::geoGraphicsMultilineItem * pU = dynamic_cast<QTVP_GEOMARKER::geoGraphicsMultilineItem *>(item);
if (pU)
{
//1.2. geo
stream.writeStartElement("geo");
QPolygonF pl = pU->llas();
int nPl = pl.size();
stream.writeAttribute("coords",QString("%1").arg(nPl));
foreach (QPointF pf, pl)
stream.writeTextElement("cod",QString("%1,%2").arg(pf.y(),0,'f',7).arg(pf.x(),0,'f',7));
stream.writeEndElement(); // geo
//1.2 style
stream.writeStartElement("style");
stream.writeTextElement("color_pen",color2string(pU->pen().color()));
stream.writeTextElement("style_pen",QString("%1").arg(int(pU->pen().style())));
stream.writeTextElement("width_pen",QString("%1").arg(int(pU->pen().width())));
stream.writeTextElement("color_brush",color2string(pU->brush().color()));
stream.writeTextElement("style_brush",QString("%1").arg(int(pU->brush().style())));
}
}
break;
......@@ -428,7 +454,11 @@ bool qtvplugin_geomarker::xml_update_mark(tag_xml_mark & mark)
}
else if (mark.type==QTVP_GEOMARKER::ITEAMTYPE_POLYGON)
{
newitem = update_polygon(name,mark.geoPoints,pen,brush);
newitem = update_polygon(name,mark.geoPoints,pen,brush,false);
}
else if (mark.type==QTVP_GEOMARKER::ITEAMTYPE_MULTILINE)
{
newitem = update_polygon(name,mark.geoPoints,pen,brush,true);
}
else if (mark.type==QTVP_GEOMARKER::ITEAMTYPE_PIXMAP)
{
......
......@@ -379,6 +379,25 @@ void testcontainer::on_pushButton_test_polygon_clicked()
"LABEL=Region;").toString();
if (res.contains("error"))
QMessageBox::information(this,"geomarker1::update_point",res);
res = ui->axWidget_map1->dynamicCall("osm_layer_call_function(QString,QString)","geomarker1",
"function=update_polygon;name=ID40;type=6;"
"lat0=42.2;lon0=-67.3;"
"lat1=34.3;lon1=-62.8;"
"lat2=22.7;lon2=-66.5;"
"lat3=11.5;lon3=-72.2;"
"lat4=0.8;lon4=-69.4;"
"style_pen=2;color_pen=0,0,255,128;"
"width_pen=3;style_brush=1;color_brush=0,255,0,128;").toString();
if (res.contains("error"))
QMessageBox::information(this,"geomarker1::update_polygon",res);
res = ui->axWidget_map1->dynamicCall("osm_layer_call_function(QString,QString)","geomarker1",
"function=update_props;name=ID40;"
"LABEL=Multiline;").toString();
if (res.contains("error"))
QMessageBox::information(this,"geomarker1::update_point",res);
}
void testcontainer::timerEvent(QTimerEvent * e)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册