Detecting border of plane in Blender Python API - python

I'm working on a script to generate building from plane. While having normal plane is rectangle it's quite easy - you're looking for vertices most -/+X, -/+Y, -/+Z, but what if plane is not of regular shape? Is there a nice easy solution within python api in Blender?
In fact is there any clever way to detect faces/edges/vertices on border?

Look for border edges: these will be ones that are only attached to one face. Look at the Mesh class, specifically the edges, faces and vertices attributes. Unfortunately the edges don’t contain a list of what faces they belong to, so you will have to construct such a mapping, e.g.
EdgeFaces = {} # mapping from edge to adjacent faces
for ThisFace in TheMesh.faces :
for ThisEdge in ThisFace.edge_keys :
if not ThisEdge in EdgeFaces :
EdgeFaces[ThisEdge] = []
#end if
EdgeFaces[ThisEdge].append(ThisFace.edge_keys)
#end for
#end for
Then you just look through EdgeFaces for all keys that map to single-element lists.

Related

Get real GPS coordinates out of known edges values on python

I'm trying to find a way to convert pixels into a real coordinates. I have an image with known (GPS) edges values.
Top left = 43.51281, -70.46223
Top right = 43.51279, -70.46213
Bottom left = 43.51272, -70.46226
Bottom right = 43.51270, -70.46215
Image with known edges values
I have another script that prints the coordinates in pixels of an image. Is there any way that the value of each corner is declared, and that it prints the real coordinates of where I clicked?
For example: The next image shape is [460, 573] and when I click somewhere on it, the pixels of that click are shown, I want it to be real coordinates.
Example
An option is to use OpenCV's getPerspectiveTransform() function, see this for an intuitive explanation of how the function maps real world coordinates to coordinates on another image (which in your case would be mapping the GPS values to the pixel values within the image):
https://towardsdatascience.com/how-to-track-football-players-using-yolo-sort-and-opencv-6c58f71120b8
And these for an example of the function being used:
Python Open CV perspectiveTransform()
https://www.geeksforgeeks.org/perspective-transformation-python-opencv/

Convert point/dot annotation in to gaussian density map

I'm studying this paper: https://papers.nips.cc/paper/2010/file/fe73f687e5bc5280214e0486b273a5f9-Paper.pdf and I'm struggling at the function below:
Basically in an image, each person will be annotated a dot rather than bounding box or segmentation. The paper proposed a way to convert a dot into Gaussian density map, which acts as a ground truth. I have try numpy.random.multivariate_normal but it seems not working.
I am working on a research problem involving density maps. This code assumes you are looping over a list of text files, where each text file has the point annotations (or you are converting from object to point annotations, like I did). It also assumes that you have a list of annotations with (x,y) centre points to work with (after reading/processing said text file).
You can find a good implementation of this here:
https://github.com/CommissarMa/MCNN-pytorch/blob/master/data_preparation/k_nearest_gaussian_kernel.py
The above has some extra code for adaptive kernels.
The below code in context (with a lot more 'fluff') is here:
https://github.com/MattSkiff/cow_flow/blob/master/data_loader.py
Here is the code I used:
# running gaussian filter over points as in crowdcount mcnn
density_map = np.zeros((img_size[1],img_size[0]), dtype=np.float32)
# add points onto basemap
for point in annotations:
base_map = np.zeros((img_size[1], img_size[0]), dtype=np.float32)
# subtract 1 to account for 0 indexing
base_map[int(round(point[1]*img_size[1])-1),
int(round(point[0]*img_size[0])-1)] += 1
density_map += scipy.ndimage.filters.gaussian_filter(base_map, sigma = sigma, mode='constant')
This should create a density map that does what you want. Using 'imshow' on an ax object from matplotlib (e.g. ax.imshow(density,cmap='hot',interpolation='nearest') should produce a density map like so (I've added the aerial image to indicate what is being labelled):

Venn3: How to reposition circles and labels?

I have made a three way venn diagram. I have three issues with it that I can't seem to solve.
What is the code to move the circle labels (i.e."Set1","Set2","Set3") because right now one is too far away from the circle.
What is the code to make the circles be three equal sizes/change the circle size?
What is the code to move the circles around the plot. Right now, set2 is within set3 (but coloured differently), I would like the diagram to look more like the "standard" way of showing a venn diagram (i.e. 3 separate circles with some overlap in the middle).
On another note, I found it difficult to find what the commands such as "set_x", "set_alpha" should be; if anyone knew of a manual that would answer by above questions I would appreciate it, I couldn't seem to find one place with all the information I needed.
import sys
import numpy
import scipy
from matplotlib_venn import venn3,venn3_circles
from matplotlib import pyplot as plt
#Build three lists to make 3 way venn diagram with
list_line = lambda x: set([line.strip() for line in open(sys.argv[x])])
set1,set2,set3 = list_line(1),list_line(2),list_line(3)
#Make venn diagram
vd = venn3([set1,set2,set3],set_labels=("Set1","Set2","Set3"))
#Colours: get the HTML codes from the net
vd.get_patch_by_id("100").set_color("#FF8000")
vd.get_patch_by_id("001").set_color("#5858FA")
vd.get_patch_by_id("011").set_color("#01DF3A")
#Move the numbers in the circles
vd.get_label_by_id("100").set_x(-0.55)
vd.get_label_by_id("011").set_x(0.1)
#Strength of color, 2.0 is very strong.
vd.get_patch_by_id("100").set_alpha(0.8)
vd.get_patch_by_id("001").set_alpha(0.6)
vd.get_patch_by_id("011").set_alpha(0.8)
plt.title("Venn Diagram",fontsize=14)
plt.savefig("output",format="pdf")
What is the code to move the circle labels (i.e."Set1","Set2","Set3") because right now one is too far away from the circle.
Something like that:
lbl = vd.get_label_by_id("A")
x, y = lbl.get_position()
lbl.set_position((x+0.1, y-0.2)) # Or whatever
The "A", "B", and "C" are predefined identifiers, denoting the three sets.
What is the code to make the circles be three equal sizes/change the circle size?
If you do not want the circle/region sizes to correspond to your data (not necessarily a good idea), you can get an unweighted ("classical") Venn diagram using the function venn3_unweighted:
from matplotlib_venn import venn3_unweighted
venn3_unweighted(...same parameters you used in venn3...)
You can further cheat and tune the result by providing a subset_areas parameter to venn3_unweighted - this is a seven-element vector specifying the desired relative size of each region. In this case the diagram will be drawn as if the region areas were subset_areas, yet the numbers will be shown from the actual subsets. Try, for example:
venn3_unweighted(...., subset_areas=(10,1,1,1,1,1,1))
What is the code to move the circles around the plot.
The need to "move the circles around" is somewhat unusual - normally you would either want the circles to be positioned so that their intersection sizes correspond to your data, or use the "default" positioning. The functions venn3 and venn3_unweighted cater to those two requirements. Moving circles around arbitrarily is possible, but would require some lower-level coding and I'd advice against that.
I found it difficult to find what the commands such as "set_x", "set_alpha" should be
The object you get when you call v.get_label_by_id is a Matplotlib Text object. You can read about its methods and properties here. The object returned by v.get_patch_by_id is a PathPatch, look here and here for reference.

How can I take a list of points that create a line and extend them into polygons inward of a certain length?

I have gps coordinates. They are just points that create an outline in a few different places, . I want to be able to have a script convert these points into polygons that extend X distance inwards, and also- a way for them to extend both inwards and outwards.
So if I had something like this:
(dots are points)
00000000000000000
00000000000000000
00............000
00.0000000000.000
00.0000000000.000
00.0000000000.000
00.0000000000.000
00.0000000000.000
00............000
00000000000000000
00000000000000000
I could run this program with a distance of 1 and "inwards", and I would end up with a polygon of # shape:
00000000000000000
00000000000000000
00&&&&&&&&&&&&000
00&&&&&&&&&&&&000
00&&00000000&&000
00&&00000000&&000
00&&00000000&&000
00&&&&&&&&&&&&000
00&&&&&&&&&&&&000
00000000000000000
00000000000000000
So far I have tried using circles and then reducing them but it seems wrong / not really feasible. This isn't being performed on a grid, actually it used floats for coordinates.
Any libraries that could do this as well are appreciated.
GDAL/OGR is another option. Ultimately what you want to do is a buffer. To expand your polygons shape outward use a buffer with a positive buffer distance, inwards it would be negative buffer distance. The following is a simple example using a shapefile. Not sure what format your data is in, but I would be surprised if GDAL/OGR can't read it.
import osgeo.ogr
# using ESRI Shape file in this example but there are a number
# of different files this lib supports: http://www.gdal.org/ogr/ogr_formats.html
driver = osgeo.ogr.GetDriverByName('ESRI Shapefile')
osgeo.ogr.UseExceptions()
# Create a data source using the driver...
dataSource = driver.Open("/home/user1/data.shp")
# Get the layer
lyr = dataSource.GetLayer()
# Select the feature in this case using an attribute query
lyr.SetAttributeFilter("column = 'value'")
# verify that you have a feature selected
print 'features in layer:', lyr.GetFeatureCount()
# get the firest feature from the layer
feature = lyr.GetNextFeature()
# get the geometry from the feature
geom = feature.GetGeometryRef()
# perform a 100 unit buffer, not sure what units the coordinates of the
# the data you have are in.
bufferGeom = geom.buffer(100)
# bufferGeom is a geometry object, which is described here:
# <http://cosmicproject.org/OGR/ogr_classes.html#Geometry>
The following is a fantastic resource for getting started with working with spatial data using GDAL/ORG: http://www.gis.usu.edu/~chrisg/python/2009/
Api docs: http://cosmicproject.org/OGR/ogr_classes.html
finally here is the link to the GDAL/OGR page. http://www.gdal.org/
https://pypi.python.org/pypi/Shapely
Shapely is a very good 2d computational geometry library; the way I understand it, it reduces your problem to a single line of code.

Find all vertices with the same edge attribute

I would like to find all vertices (vertex id's) sharing the same edge attribute (so there can be tons of vertices like this) by using Igraph. This would be very convenient when I want to find all "villages" (the vertices of my graph) on a "road", let's say "Route 69" (an edge attribute).
Is there a simple way in Igraph to do this? Maybe I've overcomplicated it.
Actually what I need is the opposite of: g.es.select(_within=g.vs[2:5]) or
>>> men = g.vs.select(gender="m")
>>> women = g.vs.select(gender="f")
>>> g.es.select(_between=(men, women))
because I know the edge attribute but I don't know the vertices.
I will select the edge and hope that it will return all related vertices.
Maybe I'm only tired now, but I don't find my way around this problem. I appreciate if somebody helps me out with the right way. Or maybe there is a method I miss in tutorial and documentation. It smells like there is a very simple method to this. Thank you in advance for any advice!
First, select all the edges on Route 69:
edges = g.es.select(name="Route69")
Then iterate through the selected edges and collect the endpoints of the vertices:
vertices = set()
for edge in edges:
vertices.update(edge.tuple)
This will give you a set containing the vertex IDs of all the vertices that are incident on at least one edge with name Route69. If you need a VertexSeq, you can simply do this:
vertices = g.vs[sorted(vertices)]
You should be able to do the following:
r69edges = g.es.select(name_eq='Route69') #Select all edges where name=='Route69'
sg = r69edges.subgraph() #Create a subgraph containing only the selected edges (and attached vertices)
village_verts = sg.vs.select(name_eq='villages') #Select the vertices where name=='villages'
This assumes that 'villages' and 'Route69' are stored in an attribute called 'name' on the vertices and edges... Adjust appropriately to match your attributes.
Of course - you can squash this all into one line if you want:
village_verts = g.es.select(name_eq='Route69').subgraph().vs.select(name_eq='villages')
Not sure if this is the most efficient way (though I'm not seeing any shortcuts in the documentation), but it should get you what you're after.

Categories