topologicpy 0.7.77__py3-none-any.whl → 0.7.79__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- topologicpy/Plotly.py +56 -43
- topologicpy/Topology.py +335 -7
- topologicpy/Vertex.py +51 -0
- topologicpy/Wire.py +12 -0
- topologicpy/version.py +1 -1
- {topologicpy-0.7.77.dist-info → topologicpy-0.7.79.dist-info}/METADATA +1 -1
- {topologicpy-0.7.77.dist-info → topologicpy-0.7.79.dist-info}/RECORD +10 -10
- {topologicpy-0.7.77.dist-info → topologicpy-0.7.79.dist-info}/LICENSE +0 -0
- {topologicpy-0.7.77.dist-info → topologicpy-0.7.79.dist-info}/WHEEL +0 -0
- {topologicpy-0.7.77.dist-info → topologicpy-0.7.79.dist-info}/top_level.txt +0 -0
topologicpy/Plotly.py
CHANGED
@@ -474,9 +474,9 @@ class Plotly:
|
|
474
474
|
x = []
|
475
475
|
y = []
|
476
476
|
z = []
|
477
|
-
|
477
|
+
sizes = []
|
478
478
|
labels = []
|
479
|
-
|
479
|
+
colors = []
|
480
480
|
label = ""
|
481
481
|
group = None
|
482
482
|
if colorKey or sizeKey or labelKey or groupKey:
|
@@ -493,58 +493,54 @@ class Plotly:
|
|
493
493
|
else:
|
494
494
|
minGroup = 0
|
495
495
|
maxGroup = 1
|
496
|
+
n = len(str(len(vertices)))
|
496
497
|
for m, v in enumerate(vertices):
|
497
498
|
x.append(v[0])
|
498
499
|
y.append(v[1])
|
499
500
|
z.append(v[2])
|
500
501
|
label = " "
|
501
502
|
group = None
|
503
|
+
colors.append(Color.AnyToHex(color))
|
504
|
+
labels.append("Vertex_"+str(m+1).zfill(n))
|
505
|
+
sizes.append(size)
|
502
506
|
if len(dictionaries) > 0:
|
503
507
|
d = dictionaries[m]
|
504
508
|
if d:
|
505
509
|
if not colorKey == None:
|
506
|
-
|
507
|
-
color = Color.AnyToHex(d_color)
|
508
|
-
groupList.append(color)
|
510
|
+
colors[m] = Dictionary.ValueAtKey(d, key=colorKey) or colors[m]
|
509
511
|
if not labelKey == None:
|
510
|
-
|
512
|
+
labels[m] = str(Dictionary.ValueAtKey(d, key=labelKey)) or labels[m]
|
511
513
|
if not sizeKey == None:
|
512
|
-
|
514
|
+
sizes[m] = Dictionary.ValueAtKey(d, key=sizeKey) or sizes[m]
|
513
515
|
if not groupKey == None:
|
514
|
-
|
516
|
+
colors[m] = Dictionary.ValueAtKey(d, key=groupKey) or colors[m]
|
515
517
|
try:
|
516
|
-
if
|
517
|
-
|
518
|
-
|
519
|
-
if
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
color = Color.ByValueInRange(group, minValue=minGroup, maxValue=maxGroup, colorScale=colorScale)
|
524
|
-
color = Color.AnyToHEX(color)
|
525
|
-
groupList.append(Color.AnyToHex(color))
|
518
|
+
if type(colors[m]) == int or type(colors[m]) == float:
|
519
|
+
if colors[m] < minGroup:
|
520
|
+
colors[m] = minGroup
|
521
|
+
if colors[m] > maxGroup:
|
522
|
+
colors[m] = maxGroup
|
523
|
+
temp_color = Color.ByValueInRange(colors[m], minValue=minGroup, maxValue=maxGroup, colorScale=colorScale)
|
524
|
+
colors[m] = Color.AnyToHEX(temp_color)
|
526
525
|
|
527
526
|
else:
|
528
|
-
|
529
|
-
|
530
|
-
groupList.append(Color.AnyToHex(color))
|
527
|
+
temp_color = Color.ByValueInRange(groups.index(colors[m]), minValue=minGroup, maxValue=maxGroup, colorScale=colorScale)
|
528
|
+
colors[m] = Color.AnyToHex(temp_color)
|
531
529
|
except:
|
532
530
|
#groupList.append(Color.AnyToHex([0,0,0]))
|
533
531
|
pass
|
534
|
-
labels.append(label)
|
535
|
-
sizeList.append(size)
|
536
532
|
else:
|
537
533
|
for v in vertices:
|
538
534
|
x.append(v[0])
|
539
535
|
y.append(v[1])
|
540
536
|
z.append(v[2])
|
541
537
|
|
542
|
-
if len(list(set(
|
543
|
-
|
538
|
+
if len(list(set(colors))) < 2:
|
539
|
+
colors = Color.AnyToHex(color)
|
544
540
|
if len(labels) < 1:
|
545
|
-
labels = ""
|
546
|
-
if len(
|
547
|
-
|
541
|
+
labels = "Vertex_1"
|
542
|
+
if len(sizes) < 1:
|
543
|
+
sizes = size
|
548
544
|
if showVertexLabel == True:
|
549
545
|
mode = "markers+text"
|
550
546
|
else:
|
@@ -554,7 +550,9 @@ class Plotly:
|
|
554
550
|
z=z,
|
555
551
|
name=legendLabel,
|
556
552
|
showlegend=showLegend,
|
557
|
-
marker=dict(color=
|
553
|
+
marker=dict(color=colors,
|
554
|
+
size=sizes,
|
555
|
+
opacity=1),
|
558
556
|
mode=mode,
|
559
557
|
legendgroup=legendGroup,
|
560
558
|
legendrank=legendRank,
|
@@ -601,13 +599,17 @@ class Plotly:
|
|
601
599
|
else:
|
602
600
|
minGroup = 0
|
603
601
|
maxGroup = 1
|
602
|
+
|
604
603
|
|
605
604
|
if colorKey or widthKey or labelKey or groupKey:
|
606
605
|
keys = [x for x in [colorKey, widthKey, labelKey, groupKey] if not x == None]
|
607
606
|
temp_dict = Helper.ClusterByKeys(edges, dictionaries, keys, silent=False)
|
608
607
|
dict_clusters = temp_dict["dictionaries"]
|
609
608
|
elements_clusters = temp_dict['elements']
|
609
|
+
n = len(str(len(elements_clusters)))
|
610
|
+
labels = []
|
610
611
|
for j, elements_cluster in enumerate(elements_clusters):
|
612
|
+
labels.append("Edge_"+str(j+1).zfill(n))
|
611
613
|
d = dict_clusters[j][0] # All dicitonaries have same values in dictionaries, so take first one.
|
612
614
|
if d:
|
613
615
|
if not colorKey == None:
|
@@ -616,7 +618,9 @@ class Plotly:
|
|
616
618
|
if not labelKey == None:
|
617
619
|
label = str(Dictionary.ValueAtKey(d, key=labelKey)) or ""
|
618
620
|
if not widthKey == None:
|
619
|
-
|
621
|
+
e_width = Dictionary.ValueAtKey(d, key=widthKey)
|
622
|
+
if not e_width == None:
|
623
|
+
width = e_width
|
620
624
|
if not groupKey == None:
|
621
625
|
group = Dictionary.ValueAtKey(d, key=groupKey)
|
622
626
|
if not group == None:
|
@@ -629,6 +633,7 @@ class Plotly:
|
|
629
633
|
else:
|
630
634
|
d_color = Color.ByValueInRange(groups.index(group), minValue=minGroup, maxValue=maxGroup, colorScale=colorScale)
|
631
635
|
color = d_color
|
636
|
+
|
632
637
|
x = []
|
633
638
|
y = []
|
634
639
|
z = []
|
@@ -639,15 +644,19 @@ class Plotly:
|
|
639
644
|
y+=[sv[1], ev[1], None] # y-coordinates of edge ends
|
640
645
|
z+=[sv[2], ev[2], None] # z-coordinates of edge ends
|
641
646
|
if showEdgeLabel == True:
|
642
|
-
mode = "lines+text"
|
647
|
+
mode = "markers+lines+text"
|
648
|
+
else:
|
649
|
+
mode = "markers+lines"
|
650
|
+
if isinstance(width, list):
|
651
|
+
marker_width = width[0]*0.25
|
643
652
|
else:
|
644
|
-
|
653
|
+
marker_width = width*0.25
|
645
654
|
trace = go.Scatter3d(x=x,
|
646
655
|
y=y,
|
647
656
|
z=z,
|
648
657
|
name=label,
|
649
658
|
showlegend=showLegend,
|
650
|
-
|
659
|
+
marker=dict(symbol="circle", size=marker_width),
|
651
660
|
mode=mode,
|
652
661
|
line=dict(color=color, width=width),
|
653
662
|
legendgroup=legendGroup,
|
@@ -869,9 +878,9 @@ class Plotly:
|
|
869
878
|
k = []
|
870
879
|
labels = []
|
871
880
|
groupList = []
|
872
|
-
faceColorList = []
|
873
881
|
label = ""
|
874
882
|
group = ""
|
883
|
+
color = Color.AnyToHex(color)
|
875
884
|
if colorKey or labelKey or groupKey:
|
876
885
|
if groups:
|
877
886
|
if len(groups) > 0:
|
@@ -886,36 +895,40 @@ class Plotly:
|
|
886
895
|
else:
|
887
896
|
minGroup = 0
|
888
897
|
maxGroup = 1
|
898
|
+
n = len(str(len(faces)))
|
889
899
|
for m, f in enumerate(faces):
|
890
900
|
i.append(f[0])
|
891
901
|
j.append(f[1])
|
892
902
|
k.append(f[2])
|
893
903
|
label = ""
|
894
904
|
group = None
|
905
|
+
groupList.append(Color.AnyToHex(color)) # Store a default color for that face
|
906
|
+
labels.append("Mace_"+str(m+1).zfill(n))
|
895
907
|
if len(dictionaries) > 0:
|
896
908
|
d = dictionaries[m]
|
897
909
|
if d:
|
910
|
+
if not colorKey == None:
|
911
|
+
d_color = Dictionary.ValueAtKey(d, key=colorKey) or color
|
912
|
+
groupList[m] = Color.AnyToHex(d_color) #Replace the default color by the dictionary color.
|
898
913
|
if not labelKey == None:
|
899
|
-
label =
|
914
|
+
label = Dictionary.ValueAtKey(d, key=labelKey)
|
915
|
+
if not label == None:
|
916
|
+
labels[m] = str(label) # Replace the default label with the dictionary label
|
900
917
|
if not groupKey == None:
|
901
918
|
group = Dictionary.ValueAtKey(d, key=groupKey) or None
|
902
919
|
|
903
920
|
if group == None:
|
904
|
-
|
905
|
-
groupList.append(f_color)
|
921
|
+
pass # do nothing because the default color will be used.
|
906
922
|
elif type(group) == int or type(group) == float:
|
907
923
|
if group < minGroup:
|
908
924
|
group = minGroup
|
909
925
|
if group > maxGroup:
|
910
926
|
group = maxGroup
|
911
927
|
f_color = Color.ByValueInRange(group, minValue=minGroup, maxValue=maxGroup, colorScale=colorScale)
|
912
|
-
|
913
|
-
groupList.append(f_color)
|
928
|
+
groupList[m] = Color.AnyToHex(f_color) # Replace the default color by the group value.
|
914
929
|
else:
|
915
930
|
f_color = Color.ByValueInRange(groups.index(group), minValue=minGroup, maxValue=maxGroup, colorScale=colorScale)
|
916
|
-
|
917
|
-
groupList.append(f_color)
|
918
|
-
labels.append(label)
|
931
|
+
groupList[m] = Color.AnyToHex(f_color)
|
919
932
|
else:
|
920
933
|
for f in faces:
|
921
934
|
i.append(f[0])
|
@@ -926,7 +939,6 @@ class Plotly:
|
|
926
939
|
groupList = None
|
927
940
|
if len(labels) < 1:
|
928
941
|
labels = ""
|
929
|
-
color = Color.AnyToHex(color)
|
930
942
|
fData = go.Mesh3d(
|
931
943
|
x = x,
|
932
944
|
y = y,
|
@@ -1030,6 +1042,7 @@ class Plotly:
|
|
1030
1042
|
if edgeColorKey or edgeWidthKey or edgeLabelKey or edgeGroupKey:
|
1031
1043
|
for tp_edge in tp_edges:
|
1032
1044
|
e_dictionaries.append(Topology.Dictionary(tp_edge))
|
1045
|
+
|
1033
1046
|
e_cluster = Cluster.ByTopologies(tp_edges)
|
1034
1047
|
geo = Topology.Geometry(e_cluster, mantissa=mantissa)
|
1035
1048
|
vertices = geo['vertices']
|
topologicpy/Topology.py
CHANGED
@@ -1509,7 +1509,9 @@ class Topology():
|
|
1509
1509
|
faces : list , optional
|
1510
1510
|
The input list of faces in the form of [i, j, k, l, ...] where the items in the list are vertex indices. The face is assumed to be closed to the last vertex is connected to the first vertex automatically.
|
1511
1511
|
topologyType : str , optional
|
1512
|
-
The desired topology type. The options are: "Vertex", "Edge", "Wire", "Face", "Shell", "Cell", "CellComplex".
|
1512
|
+
The desired highest topology type. The options are: "Vertex", "Edge", "Wire", "Face", "Shell", "Cell", "CellComplex".
|
1513
|
+
It is case insensitive. If any of these options are selected, the returned topology will only contain this type either a single topology
|
1514
|
+
or as a Cluster of these types of topologies. If set to None, a "Cluster" will be returned of vertices, edges, and/or faces. The default is None.
|
1513
1515
|
tolerance : float , optional
|
1514
1516
|
The desired tolerance. The default is 0.0001.
|
1515
1517
|
silent : bool , optional
|
@@ -1555,7 +1557,7 @@ class Topology():
|
|
1555
1557
|
output = Shell.ByFaces(faces, tolerance=tolerance) # This can return a list
|
1556
1558
|
if Topology.IsInstance(output, "Shell"):
|
1557
1559
|
return output
|
1558
|
-
elif topologyType == None:
|
1560
|
+
elif topologyType == None or topologyType== "face":
|
1559
1561
|
output = Cluster.ByTopologies(faces)
|
1560
1562
|
|
1561
1563
|
return output
|
@@ -1587,15 +1589,20 @@ class Topology():
|
|
1587
1589
|
topologyType = topologyType.lower()
|
1588
1590
|
|
1589
1591
|
if topologyType == "vertex":
|
1590
|
-
if len(topVerts)
|
1592
|
+
if len(topVerts) == 0:
|
1593
|
+
return None
|
1594
|
+
if len(topVerts) == 1:
|
1591
1595
|
return topVerts[0]
|
1592
1596
|
else:
|
1593
|
-
return
|
1597
|
+
return Cluster.ByTopologies(topVerts)
|
1594
1598
|
elif topologyType == "edge":
|
1595
|
-
if len(edges)
|
1599
|
+
if len(edges) == 0:
|
1600
|
+
return None
|
1601
|
+
if len(edges) == 1 and len(vertices) >= 2:
|
1596
1602
|
return Edge.ByVertices(topVerts[edges[0][0]], topVerts[edges[0][1]], tolerance=tolerance)
|
1597
1603
|
else:
|
1598
|
-
|
1604
|
+
topEdges = [Edge.ByVertices([topVerts[e[0]], topVerts[e[1]]], tolerance=tolerance) for e in edges]
|
1605
|
+
return Cluster.ByTopologies(topEdges)
|
1599
1606
|
|
1600
1607
|
if topologyType == "wire" and edges:
|
1601
1608
|
topEdges = [Edge.ByVertices([topVerts[e[0]], topVerts[e[1]]], tolerance=tolerance) for e in edges]
|
@@ -3635,6 +3642,325 @@ class Topology():
|
|
3635
3642
|
"""
|
3636
3643
|
return topologic.Topology.ByOcctShape(occtShape, "")
|
3637
3644
|
|
3645
|
+
@staticmethod
|
3646
|
+
def ByPDFFile(file, wires=False, faces=False, includeTypes=[], excludeTypes=[], edgeColorKey="edge_color", edgeWidthKey="edge_width", faceColorKey="face_color", faceOpacityKey="face_opacity", tolerance=0.0001, silent=False):
|
3647
|
+
"""
|
3648
|
+
Import PDF file and convert its entities to topologies.
|
3649
|
+
|
3650
|
+
Parameters
|
3651
|
+
----------
|
3652
|
+
file : file
|
3653
|
+
The input PDF file
|
3654
|
+
wires : bool , optional
|
3655
|
+
If set to True, wires will be constructed when possible. The default is True.
|
3656
|
+
faces : bool , optional
|
3657
|
+
If set to True, faces will be constructed when possible. The default is True.
|
3658
|
+
includeTypes : list , optional
|
3659
|
+
A list of PDF object types to include in the returned result. The default is [] which means all PDF objects will be included.
|
3660
|
+
The possible strings to include in this list are: ["line", "curve", "rectangle", "quadrilateral"]
|
3661
|
+
excludeTypes : list , optional
|
3662
|
+
A list of PDF object types to exclude from the returned result. The default is [] which mean no PDF object type will be excluded.
|
3663
|
+
The possible strings to include in this list are: ["line", "curve", "rectangle", "quadrilateral"]
|
3664
|
+
edgeColorKey : str , optional
|
3665
|
+
The dictionary key under which to store the edge color. The default is None.
|
3666
|
+
edgeWidthKey : str , optional
|
3667
|
+
The dictionary key under which to store the edge width. The default is None.
|
3668
|
+
faceColorKey : str , optional
|
3669
|
+
The dictionary key under which to store the face color. The default is None.
|
3670
|
+
faceOpacityKey : str , optional
|
3671
|
+
The dictionary key under which to store the face opacity. The default is None.
|
3672
|
+
tolerance : float , optional
|
3673
|
+
The desired tolerance. The default is 0.0001.
|
3674
|
+
silent : bool , optional
|
3675
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
3676
|
+
|
3677
|
+
Returns
|
3678
|
+
-------
|
3679
|
+
list
|
3680
|
+
A list of Topologic entities (edges, wires, faces, clusters) with attached dictionaries.
|
3681
|
+
|
3682
|
+
"""
|
3683
|
+
from topologicpy.Vertex import Vertex
|
3684
|
+
from topologicpy.Edge import Edge
|
3685
|
+
from topologicpy.Wire import Wire
|
3686
|
+
from topologicpy.Face import Face
|
3687
|
+
from topologicpy.Cluster import Cluster
|
3688
|
+
from topologicpy.Dictionary import Dictionary
|
3689
|
+
import os
|
3690
|
+
import warnings
|
3691
|
+
|
3692
|
+
def interpolate_bezier(control_points, num_points=50):
|
3693
|
+
"""
|
3694
|
+
Interpolate a cubic Bezier curve given control points.
|
3695
|
+
|
3696
|
+
Args:
|
3697
|
+
control_points (list): List of control points (pymupdf.Point objects).
|
3698
|
+
num_points (int): Number of points to interpolate along the curve.
|
3699
|
+
|
3700
|
+
Returns:
|
3701
|
+
list: A list of interpolated points (pymupdf.Point objects).
|
3702
|
+
"""
|
3703
|
+
p0, p1, p2, p3 = control_points
|
3704
|
+
points = [
|
3705
|
+
pymupdf.Point(
|
3706
|
+
(1 - t)**3 * p0.x + 3 * (1 - t)**2 * t * p1.x + 3 * (1 - t) * t**2 * p2.x + t**3 * p3.x,
|
3707
|
+
(1 - t)**3 * p0.y + 3 * (1 - t)**2 * t * p1.y + 3 * (1 - t) * t**2 * p2.y + t**3 * p3.y
|
3708
|
+
)
|
3709
|
+
for t in (i / num_points for i in range(num_points + 1))
|
3710
|
+
]
|
3711
|
+
return points
|
3712
|
+
|
3713
|
+
def map_types(type_list):
|
3714
|
+
type_mapping = {
|
3715
|
+
"line": "l",
|
3716
|
+
"curve": "c",
|
3717
|
+
"rect": "re",
|
3718
|
+
"quad": "qu"
|
3719
|
+
}
|
3720
|
+
return [type_mapping[key] for key in type_mapping if any(key in item for item in type_list)]
|
3721
|
+
|
3722
|
+
def remove_overlap(list1, list2):
|
3723
|
+
set1, set2 = set(list1), set(list2)
|
3724
|
+
# Remove common elements from both sets
|
3725
|
+
set1 -= set2
|
3726
|
+
set2 -= set(list1)
|
3727
|
+
return list(set1), list(set2)
|
3728
|
+
|
3729
|
+
try:
|
3730
|
+
import pymupdf # PyMuPDF
|
3731
|
+
except:
|
3732
|
+
if not silent:
|
3733
|
+
print("Topology.ByPDFFile - Warning: Installing required PyMuPDF library.")
|
3734
|
+
try:
|
3735
|
+
os.system("pip install PyMuPDF")
|
3736
|
+
except:
|
3737
|
+
os.system("pip install PyMuPDF --user")
|
3738
|
+
try:
|
3739
|
+
import pymupdf
|
3740
|
+
if not silent:
|
3741
|
+
print("Topology.ByPDFFile - Information: PyMUDF library installed correctly.")
|
3742
|
+
except:
|
3743
|
+
if not silent:
|
3744
|
+
warnings.warn("Topology.ByPDFFile - Error: Could not import PyMuPDF. Please try to install PyMuPDF manually. Returning None.")
|
3745
|
+
return None
|
3746
|
+
if not file:
|
3747
|
+
if not silent:
|
3748
|
+
print("Topology.ByPDFFile - Error: Could not open the PDF file. Returning None.")
|
3749
|
+
return None
|
3750
|
+
|
3751
|
+
if includeTypes == None:
|
3752
|
+
includeTypes = []
|
3753
|
+
if excludeTypes == None:
|
3754
|
+
excludeTypes = []
|
3755
|
+
includeTypes = [item for item in includeTypes if isinstance(item, str)]
|
3756
|
+
excludeTypes = [item for item in excludeTypes if isinstance(item, str)]
|
3757
|
+
in_types = map_types([c.lower() for c in includeTypes])
|
3758
|
+
ex_types = map_types([c.lower() for c in excludeTypes])
|
3759
|
+
in_types_1, ex_types_1 = remove_overlap(in_types, ex_types)
|
3760
|
+
if not len(in_types_1) == len(in_types) or not len(ex_types_1) == len(ex_types):
|
3761
|
+
if not silent:
|
3762
|
+
print("Topology.ByPDFFile - Warning: Ther includeTypes and excludeTypes input parameters contain overlapping elements. These have been excluded.")
|
3763
|
+
in_types = in_types_1
|
3764
|
+
|
3765
|
+
topologic_entities = []
|
3766
|
+
for page_num, page in enumerate(file, 1):
|
3767
|
+
matrix = pymupdf.Matrix(1, 1) # Identity matrix for default transformation
|
3768
|
+
paths = page.get_drawings()
|
3769
|
+
for path in paths:
|
3770
|
+
if not path.get("stroke_opacity") == 0:
|
3771
|
+
close = path.get("closePath")
|
3772
|
+
components = []
|
3773
|
+
edge_color = path.get("color", [0, 0, 0]) or [0, 0, 0]
|
3774
|
+
edge_color = [int(255 * c) for c in edge_color] # Convert stroke color to 0-255 range
|
3775
|
+
edge_width = path.get("width", 1) or 1
|
3776
|
+
face_color = path.get("fill", [1, 1, 1]) or [1,1,1]
|
3777
|
+
face_color = [int(255 * c) for c in face_color]
|
3778
|
+
face_opacity = path.get("fill_opacity", 1) or 1
|
3779
|
+
|
3780
|
+
# Create the dictionary for line width, color, fill color, and fill opacity
|
3781
|
+
keys = [edgeWidthKey, edgeColorKey, faceColorKey, faceOpacityKey]
|
3782
|
+
values = [
|
3783
|
+
edge_width,
|
3784
|
+
edge_color, # Convert stroke color to 0-255 range
|
3785
|
+
face_color, # Convert fill color to 0-255 range
|
3786
|
+
face_opacity
|
3787
|
+
]
|
3788
|
+
dictionary = Dictionary.ByKeysValues(keys, values)
|
3789
|
+
items = path.get("items") or []
|
3790
|
+
for it, item in enumerate(items):
|
3791
|
+
if (item[0] in in_types or len(in_types) == 0) and (not item[0] in ex_types):
|
3792
|
+
if item[0] == "l": # Line
|
3793
|
+
start_point = pymupdf.Point(item[1][0], item[1][1]).transform(matrix)
|
3794
|
+
end_point = pymupdf.Point(item[2][0], item[2][1]).transform(matrix)
|
3795
|
+
start_vertex = Vertex.ByCoordinates(start_point.x, -start_point.y, 0)
|
3796
|
+
end_vertex = Vertex.ByCoordinates(end_point.x, -end_point.y, 0)
|
3797
|
+
d = Vertex.Distance(start_vertex, end_vertex)
|
3798
|
+
if d > tolerance:
|
3799
|
+
edge = Edge.ByStartVertexEndVertex(start_vertex, end_vertex, tolerance=tolerance, silent=silent)
|
3800
|
+
if not edge == None:
|
3801
|
+
edge = Topology.SetDictionary(edge, dictionary) # Set dictionary
|
3802
|
+
components.append(edge)
|
3803
|
+
if it == 0:
|
3804
|
+
v_f_p = pymupdf.Point(item[1][0], item[1][1]).transform(matrix)
|
3805
|
+
very_first_vertex = Vertex.ByCoordinates(v_f_p.x, -v_f_p.y, 0)
|
3806
|
+
if it == len(items)-1 and path.get("closePath", False) == True:
|
3807
|
+
v_l_p = pymupdf.Point(item[2][0], item[2][1]).transform(matrix)
|
3808
|
+
very_last_vertex = Vertex.ByCoordinates(v_l_p.x, -v_l_p.y, 0)
|
3809
|
+
edge = Edge.ByStartVertexEndVertex(very_last_vertex, very_first_vertex, tolerance=tolerance, silent=True)
|
3810
|
+
if not edge == None:
|
3811
|
+
edge = Topology.SetDictionary(edge, dictionary) # Set dictionary
|
3812
|
+
components.append(edge)
|
3813
|
+
|
3814
|
+
elif item[0] == "c": # Bezier curve (approximated by segments)
|
3815
|
+
control_points = [pymupdf.Point(p[0], p[1]).transform(matrix) for p in item[1:]]
|
3816
|
+
bezier_points = interpolate_bezier(control_points)
|
3817
|
+
vertices = [Vertex.ByCoordinates(pt.x, -pt.y, 0) for pt in bezier_points]
|
3818
|
+
for i in range(len(vertices)-1):
|
3819
|
+
start_vertex = vertices[i]
|
3820
|
+
end_vertex = vertices[i+1]
|
3821
|
+
edge = Edge.ByStartVertexEndVertex(start_vertex, end_vertex, tolerance=tolerance, silent=False)
|
3822
|
+
if not edge == None:
|
3823
|
+
edge = Topology.SetDictionary(edge, dictionary) # Set dictionary
|
3824
|
+
components.append(edge)
|
3825
|
+
elif item[0] == "re": # Rectangle
|
3826
|
+
x0, y0, x1, y1 = item[1]
|
3827
|
+
vertices = [
|
3828
|
+
Vertex.ByCoordinates(x0, -y0, 0),
|
3829
|
+
Vertex.ByCoordinates(x1, -y0, 0),
|
3830
|
+
Vertex.ByCoordinates(x1, -y1, 0),
|
3831
|
+
Vertex.ByCoordinates(x0, -y1, 0)
|
3832
|
+
]
|
3833
|
+
for i in range(len(vertices)-1):
|
3834
|
+
start_vertex = vertices[i]
|
3835
|
+
end_vertex = vertices[i+1]
|
3836
|
+
edge = Edge.ByStartVertexEndVertex(start_vertex, end_vertex, tolerance=tolerance, silent=False)
|
3837
|
+
if not edge == None:
|
3838
|
+
edge = Topology.SetDictionary(edge, dictionary) # Set dictionary
|
3839
|
+
components.append(edge)
|
3840
|
+
edge = Edge.ByStartVertexEndVertex(vertices[-1], vertices[0], tolerance=tolerance, silent=False)
|
3841
|
+
if not edge == None:
|
3842
|
+
edge = Topology.SetDictionary(edge, dictionary) # Set dictionary
|
3843
|
+
components.append(edge)
|
3844
|
+
|
3845
|
+
elif item[0] == "qu": # Quadrilateral
|
3846
|
+
quad_points = [pymupdf.Point(pt[0], pt[1]).transform(matrix) for pt in item[1]]
|
3847
|
+
vertices = [Vertex.ByCoordinates(pt.x, -pt.y, 0) for pt in quad_points]
|
3848
|
+
for i in range(len(vertices)-1):
|
3849
|
+
start_vertex = vertices[i]
|
3850
|
+
end_vertex = vertices[i+1]
|
3851
|
+
edge = Edge.ByStartVertexEndVertex(start_vertex, end_vertex, tolerance=tolerance, silent=False)
|
3852
|
+
if not edge == None:
|
3853
|
+
edge = Topology.SetDictionary(edge, dictionary) # Set dictionary
|
3854
|
+
components.append(edge)
|
3855
|
+
edge = Edge.ByStartVertexEndVertex(vertices[-1], vertices[0], tolerance=tolerance, silent=False)
|
3856
|
+
if not edge == None:
|
3857
|
+
edge = Topology.SetDictionary(edge, dictionary) # Set dictionary
|
3858
|
+
components.append(edge)
|
3859
|
+
|
3860
|
+
if len(components) > 0:
|
3861
|
+
if len(components) == 1:
|
3862
|
+
tp_object = components[0]
|
3863
|
+
elif len(components) > 1:
|
3864
|
+
tp_object = Cluster.ByTopologies(components)
|
3865
|
+
if wires == True or faces == True:
|
3866
|
+
tp_object = Topology.SelfMerge(tp_object)
|
3867
|
+
if faces == True:
|
3868
|
+
if Topology.IsInstance(tp_object, "wire"):
|
3869
|
+
if Wire.IsClosed(tp_object):
|
3870
|
+
tp_object = Face.ByWire(tp_object, silent=True) or tp_object
|
3871
|
+
tp_object = Topology.SetDictionary(tp_object, dictionary)
|
3872
|
+
edges = Topology.Edges(tp_object)
|
3873
|
+
for edge in edges:
|
3874
|
+
edge = Topology.SetDictionary(edge, dictionary)
|
3875
|
+
topologic_entities.append(tp_object)
|
3876
|
+
|
3877
|
+
return topologic_entities
|
3878
|
+
|
3879
|
+
@staticmethod
|
3880
|
+
def ByPDFPath(path, wires=False, faces=False, includeTypes=[], excludeTypes=[], edgeColorKey="edge_color", edgeWidthKey="edge_width", faceColorKey="face_color", faceOpacityKey="face_opacity", tolerance=0.0001, silent=False):
|
3881
|
+
"""
|
3882
|
+
Import PDF file and convert its entities to topologies.
|
3883
|
+
|
3884
|
+
Parameters
|
3885
|
+
----------
|
3886
|
+
path : path
|
3887
|
+
The input path to the PDF file
|
3888
|
+
wires : bool , optional
|
3889
|
+
If set to True, wires will be constructed when possible. The default is True.
|
3890
|
+
faces : bool , optional
|
3891
|
+
If set to True, faces will be constructed when possible. The default is True.
|
3892
|
+
includeTypes : list , optional
|
3893
|
+
A list of PDF object types to include in the returned result. The default is [] which means all PDF objects will be included.
|
3894
|
+
The possible strings to include in this list are: ["line", "curve", "rectangle", "quadrilateral"]
|
3895
|
+
excludeTypes : list , optional
|
3896
|
+
A list of PDF object types to exclude from the returned result. The default is [] which mean no PDF object type will be excluded.
|
3897
|
+
The possible strings to include in this list are: ["line", "curve", "rectangle", "quadrilateral"]
|
3898
|
+
edgeColorKey : str , optional
|
3899
|
+
The dictionary key under which to store the edge color. The default is None.
|
3900
|
+
edgeWidthKey : str , optional
|
3901
|
+
The dictionary key under which to store the edge width. The default is None.
|
3902
|
+
faceColorKey : str , optional
|
3903
|
+
The dictionary key under which to store the face color. The default is None.
|
3904
|
+
faceOpacityKey : str , optional
|
3905
|
+
The dictionary key under which to store the face opacity. The default is None.
|
3906
|
+
tolerance : float , optional
|
3907
|
+
The desired tolerance. The default is 0.0001.
|
3908
|
+
silent : bool , optional
|
3909
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
3910
|
+
|
3911
|
+
Returns
|
3912
|
+
-------
|
3913
|
+
list
|
3914
|
+
A list of Topologic entities (edges, wires, faces, clusters) with attached dictionaries.
|
3915
|
+
|
3916
|
+
"""
|
3917
|
+
import os
|
3918
|
+
import warnings
|
3919
|
+
try:
|
3920
|
+
import pymupdf # PyMuPDF
|
3921
|
+
except:
|
3922
|
+
if not silent:
|
3923
|
+
print("Topology.ByPDFPath - Warning: Installing required PyMuPDF library.")
|
3924
|
+
try:
|
3925
|
+
os.system("pip install PyMuPDF")
|
3926
|
+
except:
|
3927
|
+
os.system("pip install PyMuPDF --user")
|
3928
|
+
try:
|
3929
|
+
import pymupdf
|
3930
|
+
if not silent:
|
3931
|
+
print("Topology.ByPDFPath - Information: PyMUDF library installed correctly.")
|
3932
|
+
except:
|
3933
|
+
if not silent:
|
3934
|
+
warnings.warn("Topology.ByPDFPath - Error: Could not import PyMuPDF. Please try to install PyMuPDF manually. Returning None.")
|
3935
|
+
return None
|
3936
|
+
if not isinstance(path, str):
|
3937
|
+
if not silent:
|
3938
|
+
print("Topology.ByPDFPath - Error: the input path is not a valid path. Returning None.")
|
3939
|
+
return None
|
3940
|
+
if not os.path.exists(path):
|
3941
|
+
if not silent:
|
3942
|
+
print("Topology.ByPDFPath - Error: The specified path does not exist. Returning None.")
|
3943
|
+
return None
|
3944
|
+
pdf_file = pymupdf.open(path)
|
3945
|
+
if not pdf_file:
|
3946
|
+
if not silent:
|
3947
|
+
print("Topology.ByPDFPath - Error: Could not open the PDF file. Returning None.")
|
3948
|
+
return None
|
3949
|
+
|
3950
|
+
topologies = Topology.ByPDFFile(file=pdf_file,
|
3951
|
+
wires=wires,
|
3952
|
+
faces=faces,
|
3953
|
+
includeTypes = includeTypes,
|
3954
|
+
excludeTypes = excludeTypes,
|
3955
|
+
edgeColorKey=edgeColorKey,
|
3956
|
+
edgeWidthKey=edgeWidthKey,
|
3957
|
+
faceColorKey=faceColorKey,
|
3958
|
+
faceOpacityKey=faceOpacityKey,
|
3959
|
+
tolerance=tolerance,
|
3960
|
+
silent=silent)
|
3961
|
+
pdf_file.close()
|
3962
|
+
return topologies
|
3963
|
+
|
3638
3964
|
@staticmethod
|
3639
3965
|
def ByBREPString(string):
|
3640
3966
|
"""
|
@@ -6538,7 +6864,7 @@ class Topology():
|
|
6538
6864
|
final_faces.append(f)
|
6539
6865
|
else:
|
6540
6866
|
print("Topology.RemoveCoplanarFaces - Warning: Could not remove some coplanar faces. Re-adding original faces.")
|
6541
|
-
final_faces += Shell.Faces(
|
6867
|
+
final_faces += Shell.Faces(t)
|
6542
6868
|
else: # It is a cluster
|
6543
6869
|
shells = Topology.Shells(t)
|
6544
6870
|
for shell in shells:
|
@@ -7697,6 +8023,8 @@ class Topology():
|
|
7697
8023
|
if not silent:
|
7698
8024
|
print("Topology.Show - Error: the input topologies parameter does not contain any valid topology. Returning None.")
|
7699
8025
|
return None
|
8026
|
+
if camera[0] == 0 and camera[1] == 0 and up == [0,0,1]:
|
8027
|
+
up = [0,1,0] #default to positive Y axis being up if looking down or up at the XY plane
|
7700
8028
|
data = []
|
7701
8029
|
for topology in new_topologies:
|
7702
8030
|
if Topology.IsInstance(topology, "Graph"):
|
topologicpy/Vertex.py
CHANGED
@@ -34,6 +34,57 @@ except:
|
|
34
34
|
warnings.warn("Vertex - Error: Could not import numpy.")
|
35
35
|
|
36
36
|
class Vertex():
|
37
|
+
@staticmethod
|
38
|
+
def AlignCoordinates(vertex, xList=None, yList=None, zList=None, transferDictionary=False, mantissa=6, silent=False):
|
39
|
+
"""
|
40
|
+
Aligns the coordinates of the input vertex with the list of x,y, and z coordinates.
|
41
|
+
|
42
|
+
Parameters
|
43
|
+
----------
|
44
|
+
vertex : topologic_core.Vertex
|
45
|
+
The input vertex.
|
46
|
+
xList : list , optional
|
47
|
+
The input numerical list of x-coordinates. The default is None.
|
48
|
+
yList : list , optional
|
49
|
+
The input numerical list of y-coordinates. The default is None.
|
50
|
+
zList : list , optional
|
51
|
+
The input numerical list of z-coordinates. The default is None.
|
52
|
+
transferDictionary : bool , optional
|
53
|
+
if set to True, the dictionary of the input vertex is transferred to the new vertex.
|
54
|
+
mantissa : int , optional
|
55
|
+
The desired length of the mantissa. The default is 6.
|
56
|
+
silent : bool , optional
|
57
|
+
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
58
|
+
|
59
|
+
Returns
|
60
|
+
-------
|
61
|
+
topologic_core.Vertex
|
62
|
+
The created vertex aligned to the input list of x,y, and z coordinates.
|
63
|
+
|
64
|
+
"""
|
65
|
+
from topologicpy.Topology import Topology
|
66
|
+
from topologicpy.Helper import Helper
|
67
|
+
|
68
|
+
if not Topology.IsInstance(vertex, "vertex"):
|
69
|
+
if not silent:
|
70
|
+
print("Vertex.AlignCoordinates - Error: The input vertex parameter is not a topologic vertex. Returning None.")
|
71
|
+
return None
|
72
|
+
|
73
|
+
closest_x, closest_y, closest_z = Vertex.Coordinates(vertex, mantissa=mantissa)
|
74
|
+
if isinstance(xList, list):
|
75
|
+
if len(xList) > 0:
|
76
|
+
closest_x = xList[Helper.ClosestMatch(closest_x, xList)]
|
77
|
+
if isinstance(yList, list):
|
78
|
+
if len(yList) > 0:
|
79
|
+
closest_y = yList[Helper.ClosestMatch(closest_y, yList)]
|
80
|
+
if isinstance(zList, list):
|
81
|
+
if len(zList) > 0:
|
82
|
+
closest_z = zList[Helper.ClosestMatch(closest_z, zList)]
|
83
|
+
return_vertex = Vertex.ByCoordinates(closest_x, closest_y, closest_z)
|
84
|
+
if transferDictionary == True:
|
85
|
+
return_vertex = Topology.SetDictionary(return_vertex, Topology.Dictionary(vertex), silent=silent)
|
86
|
+
return return_vertex
|
87
|
+
|
37
88
|
@staticmethod
|
38
89
|
def AreCollinear(vertices: list, mantissa: int = 6, tolerance: float = 0.0001):
|
39
90
|
"""
|
topologicpy/Wire.py
CHANGED
@@ -3039,8 +3039,20 @@ class Wire():
|
|
3039
3039
|
final_wire = Edge.ByStartVertexEndVertex(wire_verts[0], wire_verts[1], tolerance=tolerance, silent=True)
|
3040
3040
|
return final_wire
|
3041
3041
|
|
3042
|
+
if Topology.IsInstance(wire, "cluster"):
|
3043
|
+
wires = Topology.Wires(wire)
|
3044
|
+
temp_wires = []
|
3045
|
+
for w in wires:
|
3046
|
+
temp_w = Wire.RemoveCollinearEdges(w)
|
3047
|
+
if not temp_w == None:
|
3048
|
+
temp_wires.append(temp_w)
|
3049
|
+
if len(temp_wires) > 0:
|
3050
|
+
result = Topology.SelfMerge(Cluster.ByTopologies(temp_w))
|
3051
|
+
return result
|
3042
3052
|
if not Topology.IsInstance(wire, "Wire"):
|
3043
3053
|
if not silent:
|
3054
|
+
print("The wire is:", wire)
|
3055
|
+
Topology.Show(wire)
|
3044
3056
|
print("Wire.RemoveCollinearEdges - Error: The input wire parameter is not a valid wire. Returning None.")
|
3045
3057
|
curframe = inspect.currentframe()
|
3046
3058
|
calframe = inspect.getouterframes(curframe, 2)
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.7.
|
1
|
+
__version__ = '0.7.79'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.7.
|
3
|
+
Version: 0.7.79
|
4
4
|
Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
|
5
5
|
Author-email: Wassim Jabi <wassim.jabi@gmail.com>
|
6
6
|
License: AGPL v3 License
|
@@ -17,20 +17,20 @@ topologicpy/Helper.py,sha256=Sv35czP_j0oLDeJcN8usswUm4U3auiK1LQ_Z_HBvxxg,21716
|
|
17
17
|
topologicpy/Honeybee.py,sha256=HfTaEV1R8K1xOVQQy9sBOhBTF_ap8A2RxZOYhirp_Mw,21835
|
18
18
|
topologicpy/Matrix.py,sha256=umgR7An919-wGInXJ1wpqnoQ2jCPdyMe2rcWTZ16upk,8079
|
19
19
|
topologicpy/Neo4j.py,sha256=t52hgE9cVsqkGc7m7fjRsLnyfRHakVHwdvF4ms7ow78,22342
|
20
|
-
topologicpy/Plotly.py,sha256=
|
20
|
+
topologicpy/Plotly.py,sha256=cI1I6F-hGuN4dG-O-QvByipP0H1n5WsNG7_d0Y6_FNQ,113509
|
21
21
|
topologicpy/Polyskel.py,sha256=EFsuh2EwQJGPLiFUjvtXmAwdX-A4r_DxP5hF7Qd3PaU,19829
|
22
22
|
topologicpy/PyG.py,sha256=LU9LCCzjxGPUM31qbaJXZsTvniTtgugxJY7y612t4A4,109757
|
23
23
|
topologicpy/Shell.py,sha256=8OJjlWk9eCZ3uGOTht6ZVrcMczCafw-YWoDGueaz7eg,87673
|
24
24
|
topologicpy/Speckle.py,sha256=AlsGlSDuKRtX5jhVsPNSSjjbZis079HbUchDH_5RJmE,18187
|
25
25
|
topologicpy/Sun.py,sha256=42tDWMYpwRG7Z2Qjtp94eRgBuqySq7k8TgNUZDK7QxQ,36837
|
26
|
-
topologicpy/Topology.py,sha256=
|
26
|
+
topologicpy/Topology.py,sha256=nZ23yATRXAfM1d81V28qjN7yEgJIFDyCQXDxQGCe3fs,425772
|
27
27
|
topologicpy/Vector.py,sha256=A1g83zDHep58iVPY8WQ8iHNrSOfGWFEzvVeDuMnjDNY,33078
|
28
|
-
topologicpy/Vertex.py,sha256=
|
29
|
-
topologicpy/Wire.py,sha256=
|
28
|
+
topologicpy/Vertex.py,sha256=mcLJaWFCct03dkVmT25wAl6k0k2EaYvB1PWNO9WQHWg,73465
|
29
|
+
topologicpy/Wire.py,sha256=o6MlOjubkJ_f5s1tUamizCsoPKvcQ2OudtJv0yCF-2o,186477
|
30
30
|
topologicpy/__init__.py,sha256=vlPCanUbxe5NifC4pHcnhSzkmmYcs_UrZrTlVMsxcFs,928
|
31
|
-
topologicpy/version.py,sha256=
|
32
|
-
topologicpy-0.7.
|
33
|
-
topologicpy-0.7.
|
34
|
-
topologicpy-0.7.
|
35
|
-
topologicpy-0.7.
|
36
|
-
topologicpy-0.7.
|
31
|
+
topologicpy/version.py,sha256=3Y3zBNw07cgNOgxeneZYGRJ45Nq11i2jt5nPu_bH0bA,23
|
32
|
+
topologicpy-0.7.79.dist-info/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
33
|
+
topologicpy-0.7.79.dist-info/METADATA,sha256=817TOOJR836AWEB7_nU4TjReG_OHu-6KbOi3pI7jLV8,10513
|
34
|
+
topologicpy-0.7.79.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
35
|
+
topologicpy-0.7.79.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
36
|
+
topologicpy-0.7.79.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|