I propose the following way 1. Add field 'type' to your point table. 2. Fill values of this field with the values 0 (above left point), 2 (above right point), 8 (below right point), 6 (below left point). 3. In dialog layers properties select Labels and Rule-Based labeling. [![Labeling][1]][1] 4. Press Add rule (down part of the dialog in form of a plus sign). 5. Fill the field 'Label with' with the name of your table field (id in my case). 6. Press the item Placement -> Quadrant -> Field type...-> Type [![Placement][2]][2] 7. Set Distance (1 in millimeter) 8. After applying those properties you get the following picture [![Labels][3]][3] 9. In order to make placement of your labels automatically, you should add an action to the layer that contains polygons. That can be done by choosing Actions item of Layer properties. [![Add action][4]][4] 10. Press Plus button to evoke Edit action dialog. [![Edit action][5]][5] 11. Fill the proposed elements as in the picture and place the following code in the action text box import math def label_placement(bear): place = 0 if bear < 22.5 or bear > 337.5: place = 0 elif bear >= 22.5 and bear < 67.5: place = 2 elif bear >= 67.5 and bear < 112.5: place = 5 elif bear >= 112.5 and bear < 157.5: place = 8 elif bear >= 157.5 and bear < 202.5: place = 7 elif bear >= 202.5 and bear < 247.5: place = 6 elif bear >= 247.5 and bear < 292.5: place = 3 elif bear >= 292.5 and bear <= 337.5: place = 0 return place def reverse_azimuth(az): if az < 180: az += 180 else: az -= 180 return az def direct_geodetic_task(pnt, dist, bear): deg = bear * math.pi / 180 dx = dist * math.sin(deg) dy = dist * math.cos(deg) x = pnt.x() + dx y = pnt.y() + dy return QgsPoint(x, y) def point_in_poly(x, y, poly): n = len(poly) inside = False p1x = poly[0].x() p1y = poly[0].y() for i in range(n + 1): p2x = poly[i % n].x() p2y = poly[i % n].y() if y > min(p1y, p2y): if y <= max(p1y, p2y): if x <= max(p1x, p2x): if p1y != p2y: xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x if p1x == p2x or x <= xints: inside = not inside p1x, p1y = p2x, p2y return inside def clear_layer(layer): listOfIds = [feat.id() for feat in layer.getFeatures()] layer.dataProvider().deleteFeatures(listOfIds) def bisextrix_bearing(H, A, T): x0 = (H.x() + T.x()) / 2 y0 = (H.y() + T.y()) / 2 azAH = A.azimuth(H) azAT = A.azimuth(T) return (azAH + azAT) / 2.0 print "Ok" layer = None rectLayer = None layerList = QgsMapLayerRegistry.instance().mapLayersByName("point") if len(layerList) > 0: layer = layerList[0] else: print "Point table not found" layerList = QgsMapLayerRegistry.instance().mapLayersByName("rectangle") if len(layerList) > 0: rectLayer = layerList[0] else: print "Polygon table not found" print layer.name() print rectLayer.name() # clear_layer(layer) counter = 0 for feat in rectLayer.getFeatures(): polys = feat.geometry().asPolygon() poly = polys[0] if len(poly) > 3: print counter, "Vertices=", len(poly) poly_len = len(poly) for i in range(0, poly_len - 1): first_ind = i - 1 if first_ind < 0: first_ind = poly_len - 2 cr0 = poly[first_ind] cr1 = poly[i] cr2 = poly[i + 1] counter += 1 az = bisextrix_bearing(cr0, cr1, cr2) if az < 0: az = 360 + az pnt1 = direct_geodetic_task(cr1, 1, az) res = point_in_poly(pnt1.x(), pnt1.y(), poly) if res: az = reverse_azimuth(az) type = label_placement(az) tolerance = 10 searchRect = QgsRectangle(pnt1.x() - tolerance, pnt1.y() - tolerance, pnt1.x() + tolerance, pnt1.y() + tolerance) request = QgsFeatureRequest() request.setFilterRect(searchRect) cnt = 0 for ftr in layer.getFeatures(request): cnt += 1 ftr.setAttribute("type", type) layer.updateFeature(ftr) # In case no features found in the vicinity of the vertex a point feature will be generated if cnt == 0: feat = QgsFeature(layer.pendingFields()) feat.setAttribute("id", counter) feat.setAttribute("label", 'X-' + str(counter)) feat.setAttribute("type", type) feat.setGeometry(QgsGeometry.fromPoint(QgsPoint(cr1.x(), cr1.y()))) (res, outFeats) = layer.dataProvider().addFeatures([feat]) layer.triggerRepaint() 12. In fact, the python code is included as part of the project that can be found by the GitHub link [https://github.com/ulabnit07/12][6] You can find a Qgis project example.qgs and all the rest files. 13. After opening example.qgs you can try to launch the action Generate points on the layer rectangle that performs the desired function. [![Result][7]][7] Do not hesitate to ask if anything unclear from what I explained. [1]: https://i.sstatic.net/jNvMg.jpg [2]: https://i.sstatic.net/JWKW0.jpg [3]: https://i.sstatic.net/USVrM.jpg [4]: https://i.sstatic.net/RuCua.jpg [5]: https://i.sstatic.net/tiL5E.jpg [6]: https://github.com/ulabnit07/12 [7]: https://i.sstatic.net/9QkPp.jpg