def Zoom(self, zoomtype): """控制缩放的总调函数(鼠标位置获取都由内部获取) @type zoomtype: ModeKey @param zoomtype: 放大还是缩小 """ dcrect = self.GetClientRect() georect = mainDocument.geoext if zoomtype == ModeKey.ZoomInMode: # 放大 x1, y1 = ScreenPToGeoP(self.tmpxb, self.tmpyb, dcrect, georect) x2, y2 = ScreenPToGeoP(self.tmpxe, self.tmpye, dcrect, georect) if x1 == x2 and y1 == y2: realgeoext = self.__initZoomIn(x1, y1, georect) else: mgrect = GeoRect(x1, y1, x2, y2) realgeoext = self.__initZoomInRect(mgrect,dcrect.GetWidth(), \ dcrect.GetHeight()) else: # 缩小 if self.tmpxb == self.tmpxe and self.tmpyb == self.tmpye: x1, y1 = ScreenPToGeoP(self.tmpxb, self.tmpyb, dcrect, georect) realgeoext = self.__initZoomOut(x1, y1, georect) else: mrect = GeoRect(self.tmpxb, self.tmpyb, self.tmpxe, self.tmpye) realgeoext = self.__initZoomOutRect(georect, dcrect, mrect) mainDocument.geoext.ReSet(realgeoext.GetLeft(),realgeoext.GetTop(), \ realgeoext.GetRight(),realgeoext.GetBottom()) mainDocument.zoomall = 0 #self.Refresh() self.ReDraw()
def __initZoomOutRect(self, grect, dcrect, mrect): """获得调整后要缩小的矩形范围(拉框的大小和屏幕大小不成比例) @type grect: L{geosings.core.GeoRect.GeoRect} @param grect: 拉框覆盖的地理范围矩形 @type dcrect: Rect @param dcrect: 绘制区域的矩形 @type mrect: Rect @param mrect: 拉框矩形 @rtype: L{geosings.core.GeoRect.GeoRect} @return: 调整大小后需要绘制的地理区域矩形 """ mrw = mrect.GetWidth() * 1.0 mrh = mrect.GetHeight() * 1.0 dcw = dcrect.GetWidth() dch = dcrect.GetHeight() if mrw * 1.0 / mrh > dcw * 1.0 / dch: # 按宽调整 mrh = dch * 1.0 / dcw * mrw else: mrw = dcw * 1.0 / dch * mrh mrmx, mrmy = mrect.GetMiddlePoint() x = mrmx - mrw / 2 y = mrmy - mrh / 2 realw = dcw / mrw * dcw realh = dch / mrh * dch realx = -(x / dcw * realw) realy = -(y / dch * realh) realx2 = realx + realw realy2 = realy + realh realgx, realgy = ScreenPToGeoP(realx, realy, dcrect, grect) realgx2, realgy2 = ScreenPToGeoP(realx2, realy2, dcrect, grect) return GeoRect(realgx, realgy, realgx2, realgy2)
def __initZoomOut(self, x, y, georect): """ 缩小2倍 @type x,y: number @param x,y: 中点位置 @type georect: L{geosings.core.GeoRect.GeoRect} @param georect: 绘制区域所覆盖的空间区域 @rtype: L{geosings.core.GeoRect.GeoRect} @return: 缩小两倍后绘制区域所覆盖的空间范围 """ hw = georect.GetWidth() hh = georect.GetHeight() return GeoRect(x - hw, y - hh, x + hw, y + hh)
def OnLeftUp(self, evt): RectHandler.OnLeftUp(self, evt) rect = self.ctrl.GetClientRect() gwidth = self.ctrl.geoext.GetWidth() gheight = self.ctrl.geoext.GetHeight() egx, egy = ScreenPToGeoP(evt.GetX(), evt.GetY(), \ rect, self.ctrl.geoext) if self.bgx==egx or self.bgy==egy: return nowext = GeoRect(self.bgx, self.bgy, egx, egy) nowext = ExtGeoRect(nowext, rect.GetWidth(), rect.GetHeight()) self.ctrl.geoext.Set(nowext) self.ctrl.ReDraw()
def Draw(self, dc, geoext=None, all=False): """进行绘制操作时的主要函数 @type dc: wxDC @param dc: 绘制环境 @type all: bool @param all: 要不要绘制所有范围(默认为否) """ rect = self.GetClientRect() for oper in self.operh: oper.OnBDraw(dc) try: if self.map.GetLayerCount(): if self.geoext is None: self.geoext = GeoRect(0, 0, 1, 1) self.geoext.Set(self.map.allGeoExt) ge = self.__ExtRect(self.geoext, \ rect.GetWidth(),rect.GetHeight()) self.geoext.ReSet(ge[0], ge[1], ge[2], ge[3]) dc.BeginDrawing() #dc.SetDeviceOrigin(0,rect.GetHeight()-20) debug("draw geoext: %s", self.geoext) if not self.LABEL_ALONE: labelRender = LabelRender() for layer in self.map.layers: if layer.visual: render = self.__GetRender(layer) if self.LABEL_ALONE: labelRender = LabelRender() render.labelCanvas = labelRender render.Draw(dc, rect, self.geoext) if self.LABEL_ALONE: labelRender.Draw(dc, rect, self.geoext) if not self.LABEL_ALONE: labelRender.Draw(dc, rect, self.geoext) except (Exception, e): error("draw except! %s", e) for oper in self.operh: oper.OnEDraw(dc) dc.EndDrawing()
def OnLeftDown(self, evt): map = self.ctrl.map if self.ctrl.geoext is None: return rect = self.ctrl.GetClientRect() gx,gy = ScreenPToGeoP(evt.GetX(), evt.GetY(), \ rect, self.ctrl.geoext) gwidth = self.ctrl.geoext.GetWidth() gheight = self.ctrl.geoext.GetHeight() nowext = GeoRect(gx-gwidth/2.0, gy-gheight/2.0, gx+gwidth/2.0, gy+gheight/2.0) self.ctrl.geoext.Set(nowext) self.ctrl.ReDraw()
def ExtGeoRect(rect, width, height): """用长宽比来调整第一个矩形形状(中心固定) """ from geosings.core.GeoRect import GeoRect rw = rect.GetWidth() rh = rect.GetHeight() midx, midy = rect.GetMiddlePoint() if rw / rh > width * 1.0 / height: #按宽调整 newh = height * 1.0 / width * rw neww = rw else: #按高调整 neww = width * 1.0 / height * rh newh = rh return GeoRect(midx-neww/2.0,midy+newh/2.0, \ midx+neww/2.0,midy-newh/2.0)
def __initZoomInRect(self, grect, dcw, dch): """获得调整后要放大的矩形范围(拉框的大小和屏幕大小不成比例) @type grect: L{geosings.core.GeoRect.GeoRect} @param grect: 拉框覆盖的地理范围矩形 @type dcw,dch: int @param dcw,dch: 拉框的矩形的宽高 @rtype: L{geosings.core.GeoRect.GeoRect} @return: 调整大小后需要绘制的地理区域矩形 """ grw = grect.GetWidth() * 1.0 grh = grect.GetHeight() * 1.0 grmx, grmy = grect.GetMiddlePoint() if grw * 1.0 / grh > dcw * 1.0 / dch: # 按宽来调整 grh = dch * 1.0 / dcw * grw else: # 按高调整 grw = dcw * 1.0 / dch * grh return GeoRect(grmx - grw / 2, grmy - grh / 2, grmx + grw / 2, grmy + grh / 2)
def DoDrawing(self, dc, all=False): """进行重绘操作时的主要函数 @type dc: wxDC @param dc: 绘制环境 @type all: bool @param all: 要不要绘制所有范围(默认为否) """ dc.BeginDrawing() rect = self.GetClientRect() #dc.SetDeviceOrigin(0,rect.GetHeight()-20) if all: #如果要画超过屏幕范围的所有数据 nowgeoext = mainDocument.geoext allgeoext = self.map.allGeoExt dcrect = rect allw = allgeoext.GetWidth() / nowgeoext.GetWidth( ) * dcrect.GetWidth() allh = allgeoext.GetHeight() / nowgeoext.GetHeight( ) * dcrect.GetHeight() rect = GeoRect(0, 0, allw, allh) igeoext = allgeoext else: if mainDocument.zoomall and len(self.map.layers) > 0: # 如果放大到全图到屏幕 debug("zoom to all") mainDocument.initGeoExt(rect.GetWidth(), rect.GetHeight()) mainDocument.geoext = deepcopy(self.map.allGeoExt) igeoext = mainDocument.geoext self.labelCanvas = LabelCanvas() for layer in self.map.layers: if layer is not None and layer.visual: self.__DrawLayer(dc, layer, rect, igeoext) if self.map.whereFlite != "": sellyr = self.map.GetLayer(self.map.whereLayer) hlcanv = HLLayerCanvas(sellyr) hlcanv.SetWhereFilter(self.map.whereFlite, self.map.codec) hlcanv.Draw(dc, rect, igeoext) self.labelCanvas.Draw(dc, rect, igeoext) if not all: self.__DrawCross(dc, rect.GetWidth() / 2, rect.GetHeight() / 2, wx.RED) dc.EndDrawing()
def OnLeftUp(self, evt): RectHandler.OnLeftUp(self, evt) rect = self.ctrl.GetClientRect() gwidth = self.ctrl.geoext.GetWidth() gheight = self.ctrl.geoext.GetHeight() egx, egy = ScreenPToGeoP(evt.GetX(), evt.GetY(), \ rect, self.ctrl.geoext) if self.bgx==egx or self.bgy==egy: return inext = GeoRect(self.bgx, self.bgy, egx, egy) inext = ExtGeoRect(inext, rect.GetWidth(), rect.GetHeight()) scale = gwidth*1.0/inext.GetWidth() midgx, midgy = inext.GetMiddlePoint() midrx, midry = self.ctrl.geoext.GetMiddlePoint() nmidgx = midrx-(midgx-midrx)*scale nmidgy = midry+(midry-midgy)*scale xw = gwidth*scale/2.0 xh = gheight*scale/2.0 nowext = GeoRect(nmidgx-xw,nmidgy+xh,nmidgx+xw,nmidgy-xh) self.ctrl.geoext.Set(nowext) self.ctrl.ReDraw()
class MapCanvas(wx.Panel): """主画板类 """ def __init__(self, parent): """初始化 @type parent: wxCtrl @param parent: 父控件 @type mainctrl: wxCtrl @param mainctrl: 主程序 @type oparea: wxCtrl @param oparea: 输出控件 """ wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) self.parent = parent #self.mode = ModeKey.NoneMode self.map = GSSMap() cursor = wx.StockCursor(wx.CURSOR_CROSS) self.SetCursor(cursor) self.rd = 1 # 是否需要重绘? # Bind event handle to Function self.Bind(wx.EVT_PAINT, self.__OnPaint) self.Bind(wx.EVT_CHAR, self.__OnChar) self.Bind(wx.EVT_LEFT_DOWN, self.__OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.__OnLeftUp) self.Bind(wx.EVT_MOTION, self.__OnMotion) self.Bind(wx.EVT_SIZE, self.__ReSize) self.Bind(wx.EVT_IDLE, self.__OnIdle) self.LABEL_ALONE = False self.operh = [] self.moperh = None #保存operh中管mode的handler self.geoext = None #GeoRect(0,0,1,1)#用来计算绘制的地理范围 self.__do_layout() self.InitBuffer() def InitBuffer(self): """因为采用双缓存,所以要对缓存进行初始化 """ size = self.GetClientSize() self.buffer = wx.EmptyBitmap(size.width, size.height) dc = wx.BufferedDC(None, self.buffer) #dc.SetBackground(wx.Brush(self.GetBackgroundColour())) if GSSCONF["CANV_BACKGROUND_COLOR"]: dc.SetBackground(wx.Brush(GSSCONF["CANV_BACKGROUND_COLOR"])) dc.Clear() self.PrepareDC(dc) #self.DrawLines(dc) self.Draw(dc) self.rd = 0 def GetPointCoor(self, x, y): if self.geoext is not None: #geoext = mainDocument.geoext rect = self.GetClientRect() dcw = rect.GetWidth() dch = rect.GetHeight() geox,geoy = ScreenPToGeoP(x,y, \ rect,self.geoext) if GSSCONF['SHOW_COORD'] == 'G' and len(self.map.layers) > 0: map = self.map layer = map.layers[0] if layer.sr is None or layer.sr == "": return geox, geoy if type(layer.sr) == str: sr = osr.SpatialReference() sr.ImportFromWkt(layer.sr) else: sr = layer.sr if sr.IsProjected(): gcs = sr.CloneGeogCS() ct = osr.CoordinateTransformation(sr, gcs) xys = ct.TransformPoint(geox, geoy) geox, geoy = xys[0], xys[1] return geox, geoy else: return x, y def RegHandler(self, handler): debug("regHandler %s", handler) if isinstance(handler, ModeOperHandler): if self.moperh is not None: self.operh.remove(self.moperh) self.moperh = handler if handler is not None: self.operh.append(handler) def __do_layout(self): """对画板内的空间分布进行排列 """ #self.oparea.InitLayout() self.Layout() def __OnPaint(self, evt): """需要重绘时响应的事件 @type evt: wxEvent @param evt: wxEVT_PAINT事件 """ dc = wx.BufferedPaintDC(self, self.buffer) def __GetRender(self, layer): if layer.render: return layer.render elif layer.type == DataSetType.Vector: return VectorRender(layer) elif layer.type == DataSetType.Raster: return RasterRender(layer) else: return None def __ExtRect(self, rect, width, height): """用长宽比来调整第一个矩形形状(中心固定) """ rw = rect.GetWidth() rh = rect.GetHeight() midx, midy = rect.GetMiddlePoint() if rw / rh > width * 1.0 / height: #按宽调整 newh = height * 1.0 / width * rw neww = rw else: #按高调整 neww = width * 1.0 / height * rh newh = rh return [midx-neww/2.0,midy+newh/2.0, \ midx+neww/2.0,midy-newh/2.0] def Draw(self, dc, geoext=None, all=False): """进行绘制操作时的主要函数 @type dc: wxDC @param dc: 绘制环境 @type all: bool @param all: 要不要绘制所有范围(默认为否) """ rect = self.GetClientRect() for oper in self.operh: oper.OnBDraw(dc) try: if self.map.GetLayerCount(): if self.geoext is None: self.geoext = GeoRect(0, 0, 1, 1) self.geoext.Set(self.map.allGeoExt) ge = self.__ExtRect(self.geoext, \ rect.GetWidth(),rect.GetHeight()) self.geoext.ReSet(ge[0], ge[1], ge[2], ge[3]) dc.BeginDrawing() #dc.SetDeviceOrigin(0,rect.GetHeight()-20) debug("draw geoext: %s", self.geoext) if not self.LABEL_ALONE: labelRender = LabelRender() for layer in self.map.layers: if layer.visual: render = self.__GetRender(layer) if self.LABEL_ALONE: labelRender = LabelRender() render.labelCanvas = labelRender render.Draw(dc, rect, self.geoext) if self.LABEL_ALONE: labelRender.Draw(dc, rect, self.geoext) if not self.LABEL_ALONE: labelRender.Draw(dc, rect, self.geoext) except (Exception, e): error("draw except! %s", e) for oper in self.operh: oper.OnEDraw(dc) dc.EndDrawing() def SendMessage(self, msg): """画布要向外发送信息 @type msg: str @param msg: 向外发送的信息 """ from geosings.ui.core.Brain import msgParser msgParser.SendMsg(msg) result = msgParser.result if result == ActionResult.UpdateAll: #self.Refresh() self.ReDraw() else: return result def SendOrder(self, order, *arrs): """画布要向外发送的命令 @type order: str @param order: 向外发送的命令 """ from geosings.ui.core.Brain import msgParser msgParser.SendOrder(order, arrs) result = msgParser.result if result == ActionResult.UpdateAll: #self.Refresh() self.ReDraw() else: return ActionResult.Failuse #def SetMode(self,mode): # """将画布设置成某个状态 # @type mode: ModeKey # @param mode: 要将画布设置的状态 # """ # self.mode = mode # if mode == ModeKey.InfoMode: # self.ShowFTable(True) # else: # self.ShowFTable(False) # self.SetFocus() def ReDraw(self): """重新绘制当前屏幕的区域 """ self.rd = 1 self.InitBuffer() self.Refresh(True) #self.ReDrawLayer() def __OnIdle(self, evt): """没有操作时进行的响应 @type evt: wxEvent @param evt: EVT_IDLE事件 """ #print self.rd if self.rd: self.InitBuffer() self.Refresh(True) def __ReSize(self, evt): """窗口重新设置大小时的响应 @type evt: wxEvent @param evt: EVT_SIZE事件 """ #self.ReDraw() self.rd = 1 #self.ReDraw() self.Layout() #重新排列上面的组件 def __OnChar(self, evt): """键盘响应 @type evt: wxEvent @param evt: wxEVT_CHAR事件 """ #self.mainctrl.EvtOrder(evt) for oper in self.operh: oper.OnChar(evt) def __OnLeftDown(self, evt): """鼠标左键按下的响应函数 @type evt: wxEvent @param evt: 鼠标事件 """ for oper in self.operh: oper.OnLeftDown(evt) def __OnLeftUp(self, evt): """鼠标松开的时候的响应 @type evt: wxEvent @param evt: 鼠标事件 """ for oper in self.operh: oper.OnLeftUp(evt) def __OnMotion(self, evt): """鼠标移动的相应事件 @type evt: wxEvent @param evt: 鼠标事件 """ for oper in self.operh: oper.OnMotion(evt) def WinkFeatures(self, features): """闪动某(些)要素 @type features: list @param features: 要闪动的要素集合 """ dc = wx.ClientDC(self) fc = FeaturesRender(features) fc.SetWink(10) fc.BindAimFoo(self.Aim) rect = self.GetClientRect() igeoext = self.geoext fc.Draw(dc, rect, igeoext) def Aim(self, sth): """倏地瞄准某个点 @type sth: list @param sth: 要瞄准的点(或者矩形),矩形四个元素,点是两个元素 """ import time dc = wx.ClientDC(self) dcrect = self.GetClientRect() left, right = dcrect.GetLeft(), dcrect.GetRight() top, bottom = dcrect.GetTop(), dcrect.GetBottom() if len(sth) == 2: px, py = sth[0], sth[1] elif len(sth) == 4: px, py = sth[0] + sth[2] / 2, sth[1] + sth[3] / 2 else: return point = [px, py] if not (left < px < right and top < py < bottom): return hw = max(px - left, right - px) hh = max(py - top, bottom - py) hl = max(hw, hh) #计算一个要过渡的矩形范围 hllen = 50 #要移动的线的一半长度 xmove = hl / 20.0 #每次移动多少 relen = 12 #四角框的长度 dc.SetPen(wx.GREEN_PEN) if wx.Platform == "__WXGTK__": dc.SetLogicalFunction(wx.XOR) pen2 = wx.Pen(wx.WHITE, 2, wx.SOLID) dc.SetPen(pen2) self.__DrawAimLines(dc, point, hl, hllen) if len(sth) == 4: re = self.__ScaleRect(sth, 20 - 1) self.__DrawAimRect(dc, re, 0, relen) for i in range(20): for k in range(20): self.__DrawAimLines(dc, point, hl, hllen) if len(sth) == 4: re = self.__ScaleRect(sth, 20 - 1 - i) self.__DrawAimRect(dc, re, 0, relen) hl -= xmove for k in range(20): self.__DrawAimLines(dc, point, hl, hllen) if len(sth) == 4: if i < 19: re2 = self.__ScaleRect(sth, 20 - i - 2) else: re2 = self.__ScaleRect(sth, 20 - i - 1) self.__DrawAimRect(dc, re2, 0, relen) dc.SetLogicalFunction(wx.COPY) else: dc.SetLogicalFunction(wx.XOR) self.__DrawAimLines(dc, point, hl, hllen) if len(sth) == 4: re = self.__ScaleRect(sth, 20 - 1) self.__DrawAimRect(dc, re, 0, relen) for i in range(20): self.__DrawAimLines(dc, point, hl, hllen) if len(sth) == 4: re = self.__ScaleRect(sth, 20 - 1 - i) self.__DrawAimRect(dc, re, 0, relen) hl -= xmove self.__DrawAimLines(dc, point, hl, hllen) if len(sth) == 4: if i < 19: re2 = self.__ScaleRect(sth, 20 - i - 2) else: re2 = self.__ScaleRect(sth, 20 - i - 1) self.__DrawAimRect(dc, re2, 0, relen) time.sleep(0.02) dc.SetLogicalFunction(wx.COPY) def __DrawAimLines(self, dc, point, hl, hllen): dc.DrawLine(point[0] - hl - hllen - 1, point[1], point[0] - hl + hllen, point[1]) dc.DrawLine(point[0] + hl - hllen, point[1], point[0] + hl + hllen + 1, point[1]) dc.DrawLine(point[0], point[1] - hl - hllen - 1, point[0], point[1] - hl + hllen) dc.DrawLine(point[0], point[1] + hl - hllen, point[0], point[1] + hl + hllen + 1) def __DrawAimRect(self, dc, rect, hl, hllen): dc.DrawLine(rect[0], rect[1], rect[0] + hllen, rect[1]) dc.DrawLine(rect[0], rect[1], rect[0], rect[1] + hllen) dc.DrawLine(rect[0] + rect[2], rect[1], rect[0] + rect[2] - hllen, rect[1]) dc.DrawLine(rect[0] + rect[2], rect[1], rect[0] + rect[2], rect[1] + hllen) dc.DrawLine(rect[0], rect[1] + rect[3], rect[0] + hllen, rect[1] + rect[3]) dc.DrawLine(rect[0], rect[1] + rect[3], rect[0], rect[1] + rect[3] - hllen) dc.DrawLine(rect[0] + rect[2], rect[1] + rect[3], rect[0] + rect[2] - hllen, rect[1] + rect[3]) dc.DrawLine(rect[0] + rect[2], rect[1] + rect[3], rect[0] + rect[2], rect[1] + rect[3] - hllen) def __ScaleRect(self, rect, i): step = 5 return [ rect[0] - i * (step), rect[1] - i * (step), rect[2] + step * i * 2, rect[3] + step * i * 2 ]