I have multiple standard formed bricks in an IFC file of the type IfcBuildingElementProxy. While I already managed to extract their positions from the IFC file, I now struggle to get the geometry (lenght, height, widht) from the file. I know that there are 2 ways to get the geometry:
parse trough the representation attributes of the bricks and try to write a code, that calculates the geometry. This method is really exhausting, as IFC files tend to work with a lot of references. I won't go this path.
get the geometry using a engine like ifcopenshell and opencascade. I know how to cast the bricks into a TopoDS object, but struggle to find the right methods to get the geometry.
import ifcopenshell
bricklist = ifc_file.by_type('IfcBuildingElementProxy')
for brick in bricklist:
shape = ifcopenshell.geom.create_shape(settings, brick).geometry
shape.methodtogetXYZgemeometrics???
Use
settings = geom.settings()
settings.set(settings.USE_WORLD_COORDS, True) #Translates and rotates the points to their world coordinates
...
shape = geom.create_shape(settings , brick )
points=shape.geometry.verts #The xyz points
triangles=shape.geometry.faces #Indexes to the points, 3 indexes form one triangle
Note that you can also use the element's 4x3 rotation/translation matrix and do the points translation yourself if you do not use the USE_WORLD_COORDS setting. This matrix is given by
shape.transformation.matrix.data
Related
I'm working on a computer science project which is a CNC plotter basically all of the methods I see for getting Gcode uses Inkscape. I have already written software to convert Normal images to black and white edges only and I have pulled the coordinates from the image. Is there any way X,Y coordinates can be used to generate Gcode ? or would i have to use Inkscape.
GCode is just instructions called where you can pass arguments.
The machine will execute the Gcode one by one and interpret it for moving his motors or do regulation depending on his firmware.
So if you want to create Gcode in python, just create a txt file and append commands.
You need to have the Gcode availables instructions of you machine first (here InkScape).
For example in Marlin:
G1 X90.6 Y13.8 ; move to 90.6mm on the X axis and 13.8mm on the Y axis
To get this file in python:
positions = [ # Get your datas of format them like this:
[90.6, 13.8], # Point 1 [x, y]
[10.6, 3.98]
]
with open("myGCode.gcode", "w") as f:
for x, y in positions:
f.write(f"G1 X{x} Y{y} ;\n")
File created content:
G1 X90.6 Y13.8 ;
G1 X10.6 Y3.98 ;
It really depends on the machine and its controller, but most of the time,
Linear interpolation like
G1 or G01 usually only needs to be specified once, like
G01 X1.0 Y2.0;
And then its linear interpolation enabled already so it can just be
X1.0 Y3.0;
...
Up to the point where you wanna go back to rapid movement (G0 G00)
Or circular interpolation with (G02, G03)
But then it's still usually just coordinates are enough after switching
to specific interpolation once.
Yet then I assume its for simple milling and more recent mills (I was trained for Haas) has some fancy pocketing functions, where you just specify
few key points for contour and they can kinda be deducted mathematically.
It would be interesting to see your program for getting a contour out of a photo.
But specifying type of interpolation between each set of coordinates is also
OK, just it might make code readability slightly more difficult.
I've been trying to find the centers of two surfaces in my model (see photo), but don't manage to do so. They are element surfaces (faces) and there is no option in the query to find centers of element surfaces, only of element sets. Finding the center of node sets is also fine, but my node sets do not appear in the tools -> query -> mass property options.
And I can't find an option to convert my element surfaces into element sets.
What I eventually want is to find the centers of both red highlighted surfaces and draw a line between them. Can anyone help me with this?
If your surfaces contain elements then you can always retrieve them and create a set on the base of it.
m = mdb.models['myModel']
a = m.rootAssembly
es_l5_inferior_elems = a.surfaces['ES_L5INFERIOR'].elements
es_l5_inferior_elems_set = a.Set(
name='ES_L5INFERIOR_ELEMS_SET',
elements=es_l5_inferior_elems
)
If you want to get a nodes set, I am afraid you have to loop through all the elements in es_l5_inferior_elems and use the getNodes() method of a MeshElement object (keeping in mind that there will be repetitions to delete).
To get the mass/volume center you can use the dedicated method getMassProperties() of the Part or rootAssembly. By the way, to use it you do not need Sets (simply give the elements/nodes array)!
mass_prop = a.getMassProperties(regions=es_l5_inferior_elems)
print(mass_prop['volumeCentroid'])
print(mass_prop['centerOfMass'])
I have a .vtu file representing a mesh which I read through vtkXMLUnstructuredGridReader. Then I create a numpy array (nbOfPoints x 3) in which I store the mesh vertex coordinates, which I'll call meshArray.
I also have a column array (nOfPoints x 1), which I'll call brightnessArray, which represents a certain property I want to assign to the vertexes of the meshArray; so to each vertex corresponds a scalar value. For example: to the element meshArray[0] will correspond brightnessArray[0] and so on.
How can I do this?
It is then possible to interpolate the value at the vertexes of the mesh to obtain a smooth variation of the property I had set in order to visualize it in paraview?
Thank you.
Simon
Here is what you need to do :
Write a Python Programmable Source to read your numpy data as a vtkUnstructuredGrid.
Here are a few examples of programmable sources :
https://www.paraview.org/Wiki/ParaView/Simple_ParaView_3_Python_Filters
https://www.paraview.org/Wiki/Python_Programmable_Filter
Read your .vtu dataset
Use a "Ressample with Dataset" filter on your python programmable source output and select your dataset as "source"
And you're done.
The hardest part is writing the programmble source script.
Building svg file using svgwrite-1.1.9 using polyline entities.
How can I prevent flipped output?
It seems the coordinates are messed up - vertical (y) is flipped.
Here's the code I'm using to generate the polyline:
# generate svg element
line = dwg.add(dwg.polyline(
pairs,
stroke='black', fill='blue'))
Pairs is a list of tuples in cartesian coordinates (X Y pairs):
[(2228.427, 1643.919), (2419.889, 1643.919), (2419.889, 1814.927), (2431.918, 1985.935), (2216.397, 1985.935), (2228.427, 1814.927), (2228.427, 1643.919)]
I'm using InkScape to visualize the svg output, and an in-house editor to visualize an alternate data stream; the in-house version is the correct version. I'm missing one entity.
The right entity block is rotated (in source), the left one is not (but is flipped). You can see in the svg that the entire right block is also flipped vertically, so it's above where it should be.
I haven't set any user viewport/coordinates in the SVG.
I'm pretty sure XY are the same (SVG, other).
Difference between SVG and data coordinate systems is the correct answer, I can't flag Martineau as correct (not enough rep?), but this lets me post an updated graphic.
The situation follows:
Each supplier has some service areas, which the user have defined using GoogleMaps (polygons).
I need to store this data in the DB and make simple (but fast) queries over this.
Queries should looks like: "List all suppliers with service area containing x,y" or "In which polygons (service areas) x,y are inside?"
At this time, I've found GeoDjango which looks a very complex solution to this problem. To use it, I need a quite complex setup and I couldn't find any recent (and good) tutorial.
I came with this solution:
Store every polygon as a Json into the database
Apply a method to determine if some x,y belongs to any polygon
The problem with this solution is quite obvious: Queries may take too long to execute, considering I need to evaluate every polygon.
Finally: I'm looking for another solution for this problem, and I hope find something that doesn't have setup GeoDjango in my currently running server
Determine wheter some point is inside a polygon is not a problem (I found several examples); the problem is that retrieve every single polygon from DB and evaluate it does not scale. To solve that, I need to store the polygon in such way I can query it fast.
My approach.
Find centroid of polygon C++ code.
Store in database
Find longest distance from vertex to centroid (pythag)
Store as radius
Search database using centroid & radius as bounding box
If 1 or more result use point in polygon on resultant polygons
This solution enables you to store polygons outside of GeoDjango to dramatically speed up point in polygon queries.
In my case, I needed to find whether the coordinates of my numpy arrays where inside a polygon stored in my geodjango db (land/water masking). This required iterating over every coordinate combination in my arrays to test if it was inside or outside the polygon. As my arrays are large, this was taking a very long time using geodjango.
Using django's GEOSGeometry.contains my command looked something like this:
import numpy as np
from django.contrib.gis.geos import Point
my_polygon = model.geometry # get model multipolygon field
lat_lon = zip(latitude.flat, longitude.flat) # zip coordinate arrays to tuple
mask = np.array([my_polygon.contains(Point(l)) for l in lon_lat]) # boolean mask
This was taking 20 s or more on large arrays. I tried different ways of applying the geometry.contains() function over the array (e.g. np.vectorize) but this did not lead to any improvements. I then realised it was the Django contains lookup which was taking too long. I also converted the geometry to a shapely polygon and tested shapely's polygon.contains function - no difference or worse.
The solution lay in bypassing GeoDjango by using Polygon isInside method. First I created a function to create a Polygon object from my Geos Multipolygon.
from Polygon import Polygon
def multipolygon_to_polygon(multipolygon):
"""
Convert a Geos Multipolygon to python Polygon
"""
polygon = multipolygon[0] # select first polygon object
nrings = polygon.num_interior_rings # get number of rings in polygon
poly = Polygon()
poly.addContour(polygon[0].coords) # Add first ring coordinates tuple
# Add subsequent rings
if nrings > 0:
for i in range(nrings):
print("Adding ring %s" % str(i+1))
hole = True
poly.addContour(polygon[i+1].coords, hole)
return poly
Applying this to my problem
my_polygon = model.geometry # get model multipolygon field
polygon = multipolygon_to_polygon(my_polygon) # convert to python Polygon
lat_lon = zip(bands['latitude'].flat, bands['longitude'].flat) # points tuple
land_mask = array([not polygon.isInside(ll[1], ll[0]) for ll in lat_lon])
This resulted in a roughly 20X improvement in speed. Hope this helps someone.
Python 2.7.