Make Hatch object in AutoCAD by the use of COM - python

I`m working with AutoCAD drawing using Python language and comtypes library. This is fragment of my code:
from comtypes.client import *
from comtypes.automation import *
def connect_acad(self):
self.acad = GetActiveObject("AutoCAD.Application")
self.dwg = self.acad.ActiveDocument
self.mspace = self.dwg.ModelSpace
def mark_point(self, xy, num, lay):
def point(*args):
lst = [0.]*3
if len(args) < 3:
lst[0:2] = [float(x) for x in args[0:2]]
else:
lst = [float(x) for x in args[0:3]]
return VARIANT(array("d",lst))
def variant(data):
return VARIANT(VT_VARIANT, data)
def vararr(*data):
if ( len(data) == 1 and
isinstance(data, collections.Iterable) ):
data = data[0]
return map(variant, data)
p1 = point(xy[0], xy[1])
ent = self.mspace.AddCircle(p1, 0.3)
htch = self.mspace.AddHatch(0, 'SOLID', False)
htch.AppendOuterLoop(vararr([ent,]))
htch.Evaluate()
If anyone interested, full code here: https://github.com/nsedenkov/py_acadcoord/blob/master/acadcoord.py
And anything works correctly, but command htch.AppendOuterLoop raises exception "ComTypeError". Probably, anyone knows the right way to make variant array from AutoCAD graphical entitys for method AppendOuterLoop? Thank you!

The expected types are:
Type: Variant (array of Arc, Circle, Ellipse, Line, Polyline, Region, Spline objects)
And I would also recommend double check the condition:
An array of objects forming a closed boundary. The array can consist of one or more objects. If more than one object is used, their endpoints must coincide for the loop to be created properly.
See complete documentation at http://knowledge.autodesk.com/support/autocad-mechanical/getting-started/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-ActiveX/files/GUID-4CA06494-CDFF-46FA-9E1D-A0E8220F69F4-htm.html

Related

Checking most used colors in image [duplicate]

This question already has an answer here:
fastest way to find the rgb pixel color count of image
(1 answer)
Closed last month.
I want to know the list of most used colors in this picture:
I tried the following code, but it takes too long:
from PIL import Image
colors = []
class Color:
def __init__(self, m, c):
self.col = c
self.many = m
im = Image.open("~/.../strowberry.jpeg")
def cool():
for i in im.getdata():
i = str(i)
i = i.replace(", ", "")
i = i.replace("(", "")
i = i.replace(")", "")
i = int(i)
colors.append(Color(1, i))
for x in colors:
num = 0
for j in range(len(colors)):
if x.col == colors[num].col:
del colors[num]
num -= 1
x.many += 1
num += 1
for obj in colors:
print(obj.many, obj.col)
cool()
Why is the code so slow and how can I improve the performance?
Do not reinvent the wheel. The Python Standard Library contains a Counter that can do this for you much more efficiently. Using this, you don't need to iterate over the data yourself. You also do not need to define a Class and perform the string operations. The code is very short and simple:
import collections
from PIL import Image
im = Image.open('strawberry.jpg')
counter = collections.Counter(im.getdata())
for color in counter:
print(f'{counter[color]} times color {color}')
If you really need the Color objects (for whatever you want to do with it later in your program), you can easily create this from the counter object using this one-liner:
colors = [Color(counter[color], color) for color in counter]
...and if you really need it in the same string format as in your original code, use this instead:
colors = [Color(counter[color], int(''.join(map(str, color)))) for color in counter]
Note that the two one-liners make use of list comprehension, which is very Pythonic and in many cases very fast as well.
The code int(''.join(map(str, color))) does the same as your 5 lines of code in the inner loop. This uses the fact that the original data is a tuple of integers, which can be converted to strings using map(str, ...) and then concatenated together using ''.join(...).
All this together took about 0.5 second on my machine, without the printing (which is slow anyway).

OpenCV's RotatedRect has no attribute 'size' in Python3. How to work around this?

I found out that the .size.height and .size.width operators of OpenCV's RotatedRect class don't work in Python whereas they work in C++. Let me elaborate with a simplified code snippet:
cap = cv2.VideoCapture('video1.mp4')
filter = RandomClass(20)
while(cap.isOpened()):
ret, frame = cap.read() # Read a frame
res = filter.classMain(frame) # Process the frame
if (res == 0):
print('Success') # If processing completed, print Success
cap.release()
where the class definition is as follows:
import cv2
import numpy as np
class RandomClass:
def __inti__(self):
self.set_skip_first(True)
def get_skip_first(self):
return self.skip_first
def set_skip_first(self, value):
self.skip_first = value
def classMain(self, frame):
if not get_skip_first():
self.expand_minRect(100) # expand the minRect by 100 pixels
# use the expanded rectangle for some other processing here
else:
self.set_skip_first(False)
# create a mask with cv2.inRange
contour = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE, offset=(0,0))[1]
# iterate over each contour and find the index of the largest contour
self.minRect = cv2.minAreaRect(np.array(self.contours[self.largest_contour_index]))
# execute some other processing here
return 0
def expand_minRect(self, value):
self.minRect.size.height = self.minRect.size.height + value
self.minRect.size.width = self.minRect.size.width + value
The error I'm receiving is as follows. The exact lines work perfectly fine in the C++ version of the above code.
File "filename", line 106, in expand_minRect
self.minRect.size.height = self.minRect.size.height + value
AttributeError: 'tuple' object has no attribute 'size'
I tried the following. I was expecting the second printed value (of variable width2) to be greater than the first printed value (of variable width1) by value.
def expand_minRect(self, value):
_,(width1, height1),_ = self.minRect
print(width)
self.minRect[1][0] = self.minRect[1][0] + value
_,(width2,height2),_ = self.minRect
print(w)
However it didn't work as the variable type of self.minRect[1][0] is Tuple and Tuples cannot be modified.
File "filename", line 111, in expand_minRect
self.minRect1[0] = self.minRect1[0] + value
TypeError: 'tuple' object does not support item assignment
I did some research, I couldn't find a Python documentation for RotatedRect but I found a stackoverflow answer stating that
Python still lacks of RotatedRect class
So all things to a side, assuming that the RotatedRect support in Python3 is incomplete, how can I work around this and expand the width and height of my minRect variable?
According to this tutorial, minAreaRect returns a rectangle with ((center_x,center_y),(width,height),angle). Thus, if you modify your expand_minRect to recreate it with the correct components, it should work.
def expand_minRect(self, value):
self.minRect = (self.minRect[0], # keep the center
(self.minRect[1][0] + value, self.minRect[1][1] + value), # update the size
self.minRect[2]) # keep the angle
Note: The problem emerges from the fact that OpenCV python has a less object-oriented implementation than OpenCV c++. It does not return a struct which enables accessing each attribute by name (like ".size"). You need to know the tuple order and assumptions for each element.

Find closest point on mesh in specific axis (maya)

Let's say I have one locator above a polyPlane. What I want to do is a lookup or trace from the locator in negative or positive y until it hits the polyPlane and return the position of the closest point/vertex/uv/
I imagine this have been done one million times but the only examples I have found works by locating the closest point based on all axis which in my case is close to useless.
I would appreciate any help I could get!
Edit:
Added image of the difference between the first suggested solution and what I want to achieve
What we can do is use OpenMaya (Maya's API) to loop over the faceVerts gathered in an array, check to see which is shortest distance from the locator position compared to the current facevert, if it is shorter than the last shortest distance, save it as the closestVertex variable.
import maya.OpenMaya as OpenMaya
from pymel.core import *
geo = PyNode('pSphere1')
pos = PyNode('locator1').getRotatePivot(space='world')
nodeDagPath = OpenMaya.MObject()
try:
selectionList = OpenMaya.MSelectionList()
selectionList.add(geo.name())
nodeDagPath = OpenMaya.MDagPath()
selectionList.getDagPath(0, nodeDagPath)
except:
warning('OpenMaya.MDagPath() failed on %s' % geo.name())
mfnMesh = OpenMaya.MFnMesh(nodeDagPath)
pointA = OpenMaya.MPoint(pos.x, pos.y, pos.z)
pointB = OpenMaya.MPoint()
space = OpenMaya.MSpace.kWorld
util = OpenMaya.MScriptUtil()
util.createFromInt(0)
idPointer = util.asIntPtr()
mfnMesh.getClosestPoint(pointA, pointB, space, idPointer)
idx = OpenMaya.MScriptUtil(idPointer).asInt()
faceVerts = [geo.vtx[i] for i in geo.f[idx].getVertices()]
closestVertex = None
minLength = None
for v in faceVerts:
thisLength = (pos - v.getPosition(space='world')).length()
if minLength is None or thisLength < minLength:
minLength = thisLength
closestVertex = v
select(closestVertex)
This could probably be done with python without the API, but if you've got maya, you've got access to the API :)
I hope this helps

Passing Python List of Symbol Values to R Legend Call Through rpy2

I am running into a problem trying to pass a Python list to an R legend call for a plot using rpy2. I generate a list of text names and their corresponding symbols from an existing dictionary as:
dataDict = {'data':{...},
'symbols':{'xylem':14,'groundwater':17,'lagoon':16,'stream':15}}
nameListForLegend = [name for name in dataDict["symbols"]]
symbolListForLegend = [dataDict['symbols'][category] \
for category in dataDict['symbols']]
The nameListForLegend variable works in the call, but the symbolListForLegend does not:
r.legend(1.5, -42, nameListForLegend,
pch = symbolListForLegend,cex=3,col="black",border = 0)
I have tried passing it in as an R object with hacky solutions such as:
#after converting each list element to a string
symbolListString = ",".join(symbolListForLegend)
symbolListForLegend = robjects.r('list('+symbolListString+')')
All return:
RRuntimeError: Error in plot.xy(xy.coords(x, y), type = type, ...) :invalid plotting symbol
As is usually the case, I'm missing something simple here. Any help or direction to appropriate documentation would be greatly appreciated.
Thank you.
symbolListForLegend is a Python list, which has no direct conversion to an R object (although it could be an R list with default-named elements). The R function is expecting a vector.
Try:
from rpy2.robjects.vectors import IntVector
symbolListForLegend = [dataDict['symbols'][category] \
for category in dataDict['symbols']
symbolVectorForLegend = IntVector(symbolListForLegend)
r.legend(1.5, -42, nameListForLegend,
pch = symbolVectorForLegend, cex=3, col="black", border = 0)

homogenization the functions can be compiled into a calculate networks?

Inside of a network, information (package) can be passed to different node(hosts), by modify it's content it can carry different meaning. The final package depends on hosts input via it's given route of network.
Now I want to implement a calculating network model can do small jobs by give different calculate path.
Prototype:
def a(p): return p + 1
def b(p): return p + 2
def c(p): return p + 3
def d(p): return p + 4
def e(p): return p + 5
def link(p, r):
p1 = p
for x in r:
p1 = x(p1)
return p1
p = 100
route = [a,c,d]
result = link(p,result)
#========
target_result = 108
if result = target_result:
# route is OK
I think finally I need something like this:
p with [init_payload, expected_target, passed_path, actual_calculated_result]
|
\/
[CHAOS of possible of functions networks]
|
\/
px [a,a,b,c,e] # ok this path is ok and match the target
Here is my questions hope may get your help:
can p carry(determin) the route(s) by inspect the function and estmated result?
(1.1 ) for example, if on the route there's a node x()
def x(p): return x / 0 # I suppose it can pass the compile
can p know in somehow this path is not good then avoid select this path?
(1.2) Another confuse is if p is a self-defined class type, the payload inside of this class essentially is a string, when it carry with a path [a,c,d], can p know a() must with a int type then avoid to select this node?'
same as 1.2 when generating the path, can I avoid such oops
def a(p): return p + 1
def b(p): return p + 2
def x(p): return p.append(1)
def y(p): return p.append(2)
full_node_list = [a,b,x,y]
path = random(2,full_node_list) # oops x,y will be trouble for the inttype P and a,b will be trouble to list type.
pls consider if the path is lambda list of functions
PS: as the whole model is not very clear in my mind the any leading and directing will be appreciated.
THANKS!
You could test each function first with a set of sample data; any function which returns consistently unusable values might then be discarded.
def isGoodFn(f):
testData = [1,2,3,8,38,73,159] # random test input
goodEnough = 0.8 * len(testData) # need 80% pass rate
try:
good = 0
for i in testData:
if type(f(i)) is int:
good += 1
return good >= goodEnough
except:
return False
If you know nothing about what the functions do, you will have to essentially do a full breadth-first tree search with error-checking at each node to discard bad results. If you have more than a few functions this will get very large very quickly. If you can guarantee some of the functions' behavior, you might be able to greatly reduce the search space - but this would be domain-specific, requiring more exact knowledge of the problem.
If you had a heuristic measure for how far each result is from your desired result, you could do a directed search to find good answers much more quickly - but such a heuristic would depend on knowing the overall form of the functions (a distance heuristic for multiplicative functions would be very different than one for additive functions, etc).
Your functions can raise TypeError if they are not satisfied with the data types they receive. You can then catch this exception and see whether you are passing an appropriate type. You can also catch any other exception type. But trying to call the functions and catching the exceptions can be quite slow.
You could also organize your functions into different sets depending on the argument type.
functions = { list : [some functions taking a list], int : [some functions taking an int]}
...
x = choose_function(functions[type(p)])
p = x(p)
I'm somewhat confused as to what you're trying to do, but: p cannot "know about" the functions until it is run through them. By design, Python functions don't specify what type of data they operate on: e.g. a*5 is valid whether a is a string, a list, an integer or a float.
If there are some functions that might not be able to operate on p, then you could catch exceptions, for example in your link function:
def link(p, r):
try:
for x in r:
p = x(p)
except ZeroDivisionError, AttributeError: # List whatever errors you want to catch
return None
return p

Categories