Module Edge
Expand source code
# Copyright (C) 2024
# Wassim Jabi <wassim.jabi@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with
# this program. If not, see <https://www.gnu.org/licenses/>.
import topologic_core as topologic
class Edge():
@staticmethod
def Angle(edgeA, edgeB, mantissa: int = 6, bracket: bool = False) -> float:
"""
Returns the angle in degrees between the two input edges.
Parameters
----------
edgeA : topologic_core.Edge
The first input edge.
edgeB : topologic Edge
The second input edge.
mantissa : int , optional
The desired length of the mantissa. The default is 6.
bracket : bool
If set to True, the returned angle is bracketed between 0 and 180. The default is False.
Returns
-------
float
The angle in degrees between the two input edges.
"""
from topologicpy.Topology import Topology
from topologicpy.Vector import Vector
if not Topology.IsInstance(edgeA, "Edge"):
print("Edge.Angle - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
return None
if not Topology.IsInstance(edgeB, "Edge"):
print("Edge.Angle - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
return None
dirA = Edge.Direction(edgeA, mantissa)
dirB = Edge.Direction(edgeB, mantissa)
ang = Vector.Angle(dirA, dirB)
if bracket:
if ang > 90:
ang = 180 - ang
return round(ang, mantissa)
@staticmethod
def Bisect(edgeA, edgeB, length: float = 1.0, placement: int = 0, tolerance: float = 0.0001):
"""
Creates a bisecting edge between edgeA and edgeB.
Parameters
----------
edgeA : topologic_core.Edge
The first topologic Edge.
edgeB : topologic Edge
The second topologic Edge.
length : float , optional
The desired length of the bisecting edge. The default is 1.0.
placement : int , optional
The desired placement of the bisecting edge.
If set to 0, the bisecting edge centroid will be placed at the end vertex of the first edge.
If set to 1, the bisecting edge start vertex will be placed at the end vertex of the first edge.
If set to 2, the bisecting edge end vertex will be placed at the end vertex of the first edge.
If set to any number other than 0, 1, or 2, the bisecting edge centroid will be placed at the end vertex of the first edge. The default is 0.
tolerance : float , optional
The desired tolerance to decide if an Edge can be created. The default is 0.0001.
Returns
-------
topologic_core.Edge
The created bisecting edge.
"""
import numpy as np
from topologicpy.Wire import Wire
from topologicpy.Cluster import Cluster
from topologicpy.Topology import Topology
from topologicpy.Vector import Vector
if not Topology.IsInstance(edgeA, "Edge"):
print("Edge.Bisect - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
return None
if not Topology.IsInstance(edgeB, "Edge"):
print("Edge.Bisect - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
return None
if Edge.Length(edgeA) < tolerance:
print("Edge.Bisect - Error: The input edgeA parameter is shorter than the input tolerance parameter. Returning None.")
return None
if Edge.Length(edgeB) < tolerance:
print("Edge.Bisect - Error: The input edgeB parameter is shorter than the input tolerance parameter. Returning None.")
return None
wire = Topology.SelfMerge(Cluster.ByTopologies([edgeA, edgeB]), tolerance=tolerance)
if not Topology.IsInstance(wire, "Wire"):
print("Edge.Bisect - Error: The input edgeA and edgeB parameters do not share a vertex and thus cannot be bisected. Returning None.")
return None
edges = Topology.Edges(wire)
edgeA = edges[0]
edgeB = edges[1]
sv = Wire.Vertices(wire)[1]
dirA = Edge.Direction(edgeA)
dirB = Edge.Direction(edgeB)
bisecting_vector = Vector.Bisect(dirA, dirB)
ev = Topology.TranslateByDirectionDistance(sv, bisecting_vector, length)
bisecting_edge = Edge.ByVertices([sv, ev])
return bisecting_edge
@staticmethod
def ByFaceNormal(face, origin= None, length: float = 1.0, tolerance: float = 0.0001):
"""
Creates a straight edge representing the normal to the input face.
Parameters
----------
face : topologic_core.Face
The input face
origin : toopologic.Vertex , optional
The desired origin of the edge. If set to None, the centroid of the face is chosen as the origin of the edge. The default is None.
length : float , optional
The desired length of the edge. The default is 1.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
edge : topologic_core.Edge
The created edge.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Face import Face
from topologicpy.Topology import Topology
edge = None
if not Topology.IsInstance(face, "Face"):
print("Edge.ByFaceNormal - Error: The input face parameter is not a valid topologic face. Returning None.")
return None
if not Topology.IsInstance(origin, "Vertex"):
origin = Topology.Centroid(face)
if not Topology.IsInstance(origin, "Vertex"):
print("Edge.ByFaceNormal - Error: The input origin parameter is not a valid topologic origin. Returning None.")
return None
n = Face.Normal(face)
v2 = Topology.Translate(origin, n[0], n[1], n[2])
edge = Edge.ByStartVertexEndVertex(origin, v2, tolerance=tolerance, silent=True)
if not Topology.IsInstance(edge, "Edge"):
print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.")
return None
edge = Edge.SetLength(edge, length, bothSides=False)
if not Topology.IsInstance(edge, "Edge"):
print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.")
return None
return edge
@staticmethod
def ByOffset2D(edge, offset: float = 1.0, tolerance: float = 0.0001):
"""
Creates and edge offset from the input edge. This method is intended for edges that are in the XY plane.
Parameters
----------
edge : topologic_core.Edge
The input edge.
offset : float , optional
The desired offset. The default is 1.
tolerance : float , optiona
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
An edge offset from the input edge.
"""
from topologicpy.Topology import Topology
from topologicpy.Vector import Vector
n = Edge.Normal(edge)
n = Vector.Normalize(n)
n = Vector.Multiply(n, offset, tolerance)
edge = Topology.Translate(edge, n[0], n[1], n[2])
return edge
@staticmethod
def ByStartVertexEndVertex(vertexA, vertexB, tolerance: float = 0.0001, silent=False):
"""
Creates a straight edge that connects the input vertices.
Parameters
----------
vertexA : topologic_core.Vertex
The first input vertex. This is considered the start vertex.
vertexB : toopologic.Vertex
The second input vertex. This is considered the end vertex.
tolerance : float , optional
The desired tolerance to decide if an Edge can be created. The default is 0.0001.
silent : bool , optional
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
Returns
-------
edge : topologic_core.Edge
The created edge.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Topology import Topology
edge = None
if not Topology.IsInstance(vertexA, "Vertex"):
if not silent:
print("Edge.ByStartVertexEndVertex - Error: The input vertexA parameter is not a valid topologic vertex. Returning None.")
return None
if not Topology.IsInstance(vertexB, "Vertex"):
if not silent:
print("Edge.ByStartVertexEndVertex - Error: The input vertexB parameter is not a valid topologic vertex. Returning None.")
return None
if Topology.IsSame(vertexA, vertexB):
if not silent:
print("Edge.ByStartVertexEndVertex - Error: The input vertexA and vertexB parameters are the same vertex. Returning None.")
return None
if Vertex.Distance(vertexA, vertexB) < tolerance:
if not silent:
print("Edge.ByStartVertexEndVertex - Error: The distance between the input vertexA and vertexB parameters is less than the input tolerance. Returning None.")
return None
try:
edge = topologic.Edge.ByStartVertexEndVertex(vertexA, vertexB) # Hook to Core
except:
if not silent:
print("Edge.ByStartVertexEndVertex - Error: Could not create an edge. Returning None.")
edge = None
return edge
@staticmethod
def ByVertices(*args, tolerance: float = 0.0001, silent: bool = False):
"""
Creates a straight edge that connects the input list of vertices.
Parameters
----------
vertices : list
The input list of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
tolerance : float , optional
The desired tolerance to decide if an edge can be created. The default is 0.0001.
silent : bool , optional
If set to True, error and warning messages are printed. Otherwise, they are not. The default is True.
Returns
-------
topologic_core.Edge
The created edge.
"""
from topologicpy.Helper import Helper
from topologicpy.Topology import Topology
if len(args) == 0:
print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.")
return None
if len(args) == 1:
vertices = args[0]
if isinstance(vertices, list):
if len(vertices) == 0:
if not silent:
print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.")
return None
else:
vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")]
if len(vertexList) == 0:
if not silent:
print("Edge.ByVertices - Error: The input vertices parameter does not contain any valid vertices. Returning None.")
return None
else:
if not silent:
print("Edge.ByVertices - Warning: The input vertices parameter contains only one vertex. Returning None.")
return None
else:
vertexList = Helper.Flatten(list(args))
vertexList = [x for x in vertexList if Topology.IsInstance(x, "Vertex")]
if len(vertexList) < 2:
if not silent:
print("Edge.ByVertices - Error: The input vertices parameter has less than two vertices. Returning None.")
return None
return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance, silent=silent)
@staticmethod
def ByVerticesCluster(cluster, tolerance: float = 0.0001):
"""
Creates a straight edge that connects the input cluster of vertices.
Parameters
----------
cluster : topologic_core.Cluster
The input cluster of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
tolerance : float , optional
The desired tolerance to decide if an edge can be created. The default is 0.0001.
Returns
-------
topologic_core.Edge
The created edge.
"""
from topologicpy.Cluster import Cluster
from topologicpy.Topology import Topology
if not Topology.IsInstance(cluster, "Cluster"):
print("Edge.ByVerticesCluster - Error: The input cluster parameter is not a valid topologic cluster. Returning None.")
return None
vertices = Cluster.Vertices(cluster)
vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")]
if len(vertexList) < 2:
print("Edge.ByVerticesCluster - Error: The input cluster parameter contains less than two vertices. Returning None.")
return None
return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance)
@staticmethod
def Direction(edge, mantissa: int = 6) -> list:
"""
Returns the direction of the input edge expressed as a list of three numbers.
Parameters
----------
edge : topologic_core.Edge
The input edge.
mantissa : int , optional
The desired length of the mantissa. The default is 6.
Returns
-------
list
The direction of the input edge.
"""
from topologicpy.Vector import Vector
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Direction - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
ev = edge.EndVertex()
sv = edge.StartVertex()
x = ev.X() - sv.X()
y = ev.Y() - sv.Y()
z = ev.Z() - sv.Z()
uvec = Vector.Normalize([x,y,z])
x = round(uvec[0], mantissa)
y = round(uvec[1], mantissa)
z = round(uvec[2], mantissa)
return [x, y, z]
@staticmethod
def EndVertex(edge):
"""
Returns the end vertex of the input edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
Returns
-------
topologic_core.Vertex
The end vertex of the input edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.EndVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
vert = None
try:
vert = edge.EndVertex()
except:
vert = None
return vert
@staticmethod
def Extend(edge, distance: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001):
"""
Extends the input edge by the input distance.
Parameters
----------
edge : topologic_core.Edge
The input edge.
distance : float , optional
The offset distance. The default is 1.
bothSides : bool , optional
If set to True, the edge will be extended by half the distance at each end. The default is False.
reverse : bool , optional
If set to True, the edge will be extended from its start vertex. Otherwise, it will be extended from its end vertex. The default is False.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The extended edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Extend - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
distance = abs(distance)
if distance < tolerance:
return edge
sv = Edge.StartVertex(edge)
ev = Edge.EndVertex(edge)
if bothSides:
sve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=sv, tolerance=tolerance)
eve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=ev, tolerance=tolerance)
elif reverse:
sve = Edge.VertexByDistance(edge, distance=-distance, origin=sv, tolerance=tolerance)
eve = Edge.EndVertex(edge)
else:
sve = Edge.StartVertex(edge)
eve = Edge.VertexByDistance(edge, distance=distance, origin=ev, tolerance=tolerance)
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
@staticmethod
def ExtendToEdge2D(edgeA, edgeB, tolerance: float = 0.0001):
"""
Extends the first input edge to meet the second input edge. This works only in the XY plane. Z coordinates are ignored.
Parameters
----------
edgeA : topologic_core.Edge
The first input edge.
edgeB : topologic_core.Edge
The second input edge.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The extended edge.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Topology import Topology
if not Topology.IsInstance(edgeA, "Edge"):
print("Edge.ExtendToEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
return None
if not Topology.IsInstance(edgeB, "Edge"):
print("Edge.ExtendToEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
return None
sva = Edge.StartVertex(edgeA)
eva = Edge.EndVertex(edgeA)
intVertex = Edge.Intersect2D(edgeA, edgeB)
if intVertex and not (Vertex.IsInternal(intVertex, edgeA)):
e1 = Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True)
e2 = Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
l1 = Edge.Length(e1)
l2 = Edge.Length(e2)
if l1 > l2:
return e1
else:
return e2
print("Edge.ExtendToEdge2D - Error: The operation failed. Returning None.")
return None
@staticmethod
def Index(edge, edges: list, strict: bool = False, tolerance: float = 0.0001) -> int:
"""
Returns index of the input edge in the input list of edges
Parameters
----------
edge : topologic_core.Edge
The input edge.
edges : list
The input list of edges.
strict : bool , optional
If set to True, the edge must be strictly identical to the one found in the list. Otherwise, a distance comparison is used. The default is False.
tolerance : float , optional
The tolerance for computing if the input edge is identical to an edge from the list. The default is 0.0001.
Returns
-------
int
The index of the input edge in the input list of edges.
"""
from topologicpy.Topology import Topology
from topologicpy.Vertex import Vertex
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Index - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
if not isinstance(edges, list):
print("Edge.Index - Error: The input edges parameter is not a valid list. Returning None.")
return None
edges = [e for e in edges if Topology.IsInstance(e, "Edge")]
if len(edges) < 1:
print("Edge.Index - Error: The input edges parameter contains no valid edges. Returning None.")
return None
sva = Edge.StartVertex(edge)
eva = Edge.EndVertex(edge)
for i in range(len(edges)):
if strict:
if Topology.IsSame(edge, edges[i]):
return i
else:
svb = Edge.StartVertex(edges[i])
evb = Edge.EndVertex(edges[i])
dsvsv = Vertex.Distance(sva, svb)
devev = Vertex.Distance(eva, evb)
if dsvsv < tolerance and devev < tolerance:
return i
dsvev = Vertex.Distance(sva, evb)
devsv = Vertex.Distance(eva, svb)
if dsvev < tolerance and devsv < tolerance:
return i
return None
@staticmethod
def Intersect2D(edgeA, edgeB, silent: bool = False):
"""
Returns the intersection of the two input edges as a topologic_core.Vertex. This works only in the XY plane. Z coordinates are ignored.
Parameters
----------
edgeA : topologic_core.Edge
The first input edge.
edgeB : topologic_core.Edge
The second input edge.
silent : bool , optional
If set to False, error and warning messages are displayed. Otherwise they are not. The default is False.
Returns
-------
topologic_core.Vertex
The intersection of the two input edges.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Topology import Topology
if not Topology.IsInstance(edgeA, "Edge"):
if not silent:
print("Edge.Intersect2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
return None
if not Topology.IsInstance(edgeB, "Edge"):
if not silent:
print("Edge.Intersect2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
return None
sva = Edge.StartVertex(edgeA)
eva = Edge.EndVertex(edgeA)
svb = Edge.StartVertex(edgeB)
evb = Edge.EndVertex(edgeB)
# Line AB represented as a1x + b1y = c1
a1 = Vertex.Y(eva) - Vertex.Y(sva)
b1 = Vertex.X(sva) - Vertex.X(eva)
c1 = a1*(Vertex.X(sva)) + b1*(Vertex.Y(sva))
# Line CD represented as a2x + b2y = c2
a2 = Vertex.Y(evb) - Vertex.Y(svb)
b2 = Vertex.X(svb) - Vertex.X(evb)
c2 = a2*(Vertex.X(svb)) + b2*(Vertex.Y(svb))
determinant = a1*b2 - a2*b1
if (determinant == 0):
# The lines are parallel. This is simplified
# by returning a pair of FLT_MAX
if not silent:
print("Edge.Intersect2D - Warning: The input edgeA and edgeB parameters are parallel edges. Returning None.")
return None
else:
x = (b2*c1 - b1*c2)/determinant
y = (a1*c2 - a2*c1)/determinant
return Vertex.ByCoordinates(x,y,0)
@staticmethod
def IsCollinear(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001) -> bool:
"""
Return True if the two input edges are collinear. Returns False otherwise.
This code is based on a contribution by https://github.com/gaoxipeng
Parameters
----------
edgeA : topologic_core.Edge
The first input edge.
edgeB : topologic_core.Edge
The second input edge.
mantissa : int , optional
The desired length of the mantissa. The default is 6.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
bool
True if the two edges are collinear. False otherwise.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Topology import Topology
import numpy as np
if not Topology.IsInstance(edgeA, "Edge"):
print("Edge.IsCollinear - Error: The input parameter edgeA is not a valid edge. Returning None")
return None
if not Topology.IsInstance(edgeB, "Edge"):
print("Edge.IsCollinear - Error: The input parameter edgeB is not a valid edge. Returning None")
return None
if Edge.Length(edgeA) < tolerance:
print("Edge.IsCollinear - Error: The length of edgeA is less than the tolerance. Returning None")
return None
if Edge.Length(edgeB) < tolerance:
print("Edge.IsCollinear - Error: The length of edgeB is less than the tolerance. Returning None")
return None
# Get start and end points of the first edge
start_a = Edge.StartVertex(edgeA)
end_a = Edge.EndVertex(edgeA)
start_a_coords = np.array([Vertex.X(start_a), Vertex.Y(start_a), Vertex.Z(start_a)])
end_a_coords = np.array(
[Vertex.X(end_a, mantissa=mantissa), Vertex.Y(end_a, mantissa=mantissa), Vertex.Z(end_a, mantissa=mantissa)])
# Calculate the direction vector of the first edge
direction_a = end_a_coords - start_a_coords
# Normalize the direction vector
norm_a = np.linalg.norm(direction_a)
if norm_a == 0:
print("Edge.IsCollinear - Error: Division by zero. Returning None.")
return None
direction_a /= norm_a
# Function to calculate perpendicular distance from a point to the line defined by a point and direction vector
def distance_from_line(point, line_point, line_dir):
point = np.array([Vertex.X(point, mantissa=mantissa), Vertex.Y(point, mantissa=mantissa),
Vertex.Z(point, mantissa=mantissa)])
line_point = np.array(line_point)
diff = point - line_point
cross_product = np.cross(diff, line_dir)
line_dir_norm = np.linalg.norm(line_dir)
if line_dir_norm == 0:
print("Edge.IsCollinear - Error: Division by zero. Returning None.")
return None
distance = np.linalg.norm(cross_product) / np.linalg.norm(line_dir)
return distance
# Get start and end points of the second edge
start_b = Edge.StartVertex(edgeB)
end_b = Edge.EndVertex(edgeB)
# Calculate distances for start and end vertices of the second edge to the line defined by the first edge
distance_start = distance_from_line(start_b, start_a_coords, direction_a)
distance_end = distance_from_line(end_b, start_a_coords, direction_a)
# Check if both distances are within tolerance
return bool(distance_start < tolerance) and bool(distance_end < tolerance)
@staticmethod
def IsParallel(edgeA, edgeB, mantissa: int = 6, angTolerance: float = 0.1) -> bool:
"""
Return True if the two input edges are parallel. Returns False otherwise.
Parameters
----------
edgeA : topologic_core.Edge
The first input edge.
edgeB : topologic_core.Edge
The second input edge.
mantissa : int , optional
The desired length of the mantissa. The default is 6.
angTolerance : float , optional
The angular tolerance used for the test. The default is 0.1.
Returns
-------
bool
True if the two edges are collinear. False otherwise.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edgeA, "Edge"):
print("Edge.IsParallel - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
return None
if not Topology.IsInstance(edgeB, "Edge"):
print("Edge.IsParallel - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
return None
ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True)
if abs(ang) < angTolerance or abs(180 - ang) < angTolerance:
return True
return False
@staticmethod
def Length(edge, mantissa: int = 6) -> float:
"""
Returns the length of the input edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
mantissa : int , optional
The desired length of the mantissa. The default is 6.
Returns
-------
float
The length of the input edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Length - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
length = None
try:
length = round(topologic.EdgeUtility.Length(edge), mantissa) # Hook to Core
except:
length = None
if length == None:
print("Edge.Length - Error: Could not compute the length of the input edge parameter. Returning None.")
return length
@staticmethod
def Line(origin= None, length: float = 1, direction: list = [1,0,0], placement: str ="center", tolerance: float = 0.0001):
"""
Creates a straight edge (line) using the input parameters.
Parameters
----------
origin : topologic_core.Vertex , optional
The origin location of the box. The default is None which results in the edge being placed at (0, 0, 0).
length : float , optional
The desired length of the edge. The default is 1.0.
direction : list , optional
The desired direction (vector) of the edge. The default is [1,0,0] (along the X-axis).
placement : str , optional
The desired placement of the edge. The options are:
1. "center" which places the center of the edge at the origin.
2. "start" which places the start of the edge at the origin.
3. "end" which places the end of the edge at the origin.
The default is "center".
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The created edge
"""
from topologicpy.Vertex import Vertex
from topologicpy.Vector import Vector
from topologicpy.Topology import Topology
if origin == None:
origin = Vertex.Origin()
if not Topology.IsInstance(origin, "Vertex"):
print("Edge.Line - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
return None
if length <= 0:
print("Edge.Line - Error: The input length is less than or equal to zero. Returning None.")
return None
if not isinstance(direction, list):
print("Edge.Line - Error: The input direction parameter is not a valid list. Returning None.")
return None
if not len(direction) == 3:
print("Edge.Line - Error: The length of the input direction parameter is not equal to three. Returning None.")
return None
direction = Vector.Normalize(direction)
if "center" in placement.lower():
sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length*0.5)
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
if "start" in placement.lower():
sv = origin
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
if "end" in placement.lower():
sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length)
ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length)
return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True)
else:
print("Edge.Line - Error: The input placement string is not one of center, start, or end. Returning None.")
return None
@staticmethod
def Normal(edge, angle: float = 0.0):
"""
Returns the normal (perpendicular) vector to the input edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
angle : float , optional
The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge
by the angle value around the axis defined by the input edge. The default is 0.0.
Returns
-------
list
The normal (perpendicular ) vector to the input edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Normal - Error: The input edge parameter is not a valid edge. Returning None.")
return None
normal_edge = Edge.NormalAsEdge(edge, length=1.0, u=0.5, angle=angle)
return Edge.Direction(normal_edge)
@staticmethod
def NormalAsEdge(edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0):
"""
Returns the normal (perpendicular) vector to the input edge as an edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
length : float , optional
The desired length of the normal edge. The default is 1.0.
u : float , optional
The desired u parameter placement of the normal edge. A value of 0.0 places the normal edge
at the start vertex of the input edge, a value of 0.5 places the normal edge
at the midpoint of the input edge, and a value of 1.0 places the normal edge
at the end vertex of the input edge. The default is 0.5
angle : float , optional
The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge
by the angle value around the axis defined by the input edge. The default is 0.0.
Returns
-------
topologic_core.Edge
The normal (perpendicular) vector to the input edge as an edge.
"""
import numpy as np
from numpy.linalg import norm
import topologic_core as topologic
from topologicpy.Vertex import Vertex
from topologicpy.Topology import Topology
def calculate_normal(start_vertex, end_vertex):
start_vertex = [float(x) for x in start_vertex]
end_vertex = [float(x) for x in end_vertex]
# Calculate the direction vector of the line segment
direction_vector = np.array(end_vertex) - np.array(start_vertex)
# Calculate the normal vector by swapping components and negating one of them
normal_vector = np.array([-direction_vector[1], direction_vector[0], 0])
# Normalize the normal vector
normal_vector /= norm(normal_vector)
return normal_vector
def calculate_normal_line(start_vertex, end_vertex):
# Calculate the normal vector of the line
normal_vector = calculate_normal(start_vertex, end_vertex)
# Calculate the new end vertex for the normal line to have a length of 1
normal_end_vertex = np.array(start_vertex) + normal_vector
# Return the start and end vertices of the normal line
return start_vertex, list(normal_end_vertex)
if not Topology.IsInstance(edge, "Edge"):
print("Edge.NormalAsEdge - Error: The input edge parameter is not a valid edge. Returning None.")
return None
if length <= 0.0:
print("Edge.NormalAsEdge - Error: The input length parameter is not a positive number greater than zero. Returning None.")
return None
edge_direction = Edge.Direction(edge)
x, y, z = edge_direction
start_vertex = Vertex.Coordinates(Edge.StartVertex(edge))
end_vertex = Vertex.Coordinates(Edge.EndVertex(edge))
normal_line_start, normal_line_end = calculate_normal_line(start_vertex, end_vertex)
sv = Vertex.ByCoordinates(normal_line_start)
ev = Vertex.ByCoordinates(list(normal_line_end))
normal_edge = Edge.ByVertices([sv, ev])
normal_edge = Edge.SetLength(normal_edge, length, bothSides=False)
normal_edge = Topology.Rotate(normal_edge, origin=Edge.StartVertex(normal_edge), axis=[x,y,z], angle=angle)
dist = Edge.Length(edge)*u
normal_edge = Topology.TranslateByDirectionDistance(normal_edge, edge_direction, dist)
return normal_edge
@staticmethod
def Normalize(edge, useEndVertex: bool = False, tolerance: float = 0.0001):
"""
Creates a normalized edge that has the same direction as the input edge, but a length of 1.
Parameters
----------
edge : topologic_core.Edge
The input edge.
useEndVertex : bool , optional
If True the normalized edge end vertex will be placed at the end vertex of the input edge. Otherwise, the normalized edge start vertex will be placed at the start vertex of the input edge. The default is False.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The normalized edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Normalize - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
if not useEndVertex:
sv = edge.StartVertex()
ev = Edge.VertexByDistance(edge, 1.0, edge.StartVertex())
else:
sv = Edge.VertexByDistance(edge, 1.0, edge.StartVertex())
ev = edge.EndVertex()
return Edge.ByVertices([sv, ev], tolerance=tolerance)
@staticmethod
def ParameterAtVertex(edge, vertex, mantissa: int = 6, silent: bool = False) -> float:
"""
Returns the *u* parameter along the input edge based on the location of the input vertex.
Parameters
----------
edge : topologic_core.Edge
The input edge.
vertex : topologic_core.Vertex
The input vertex.
mantissa : int , optional
The desired length of the mantissa. The default is 6.
silent : bool , optional
If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
Returns
-------
float
The *u* parameter along the input edge based on the location of the input vertex.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
if not silent:
print("Edge.ParameterAtVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
if not Topology.IsInstance(vertex, "Vertex"):
if not silent:
print("Edge.ParameterAtVertex - Error: The input vertex parameter is not a valid topologic vertex. Returning None.")
return None
parameter = None
try:
parameter = topologic.EdgeUtility.ParameterAtPoint(edge, vertex) # Hook to Core
except:
return None #Return silently because topologic C++ returns a runtime error if point is not on curve.
return round(parameter, mantissa)
@staticmethod
def Reverse(edge, tolerance: float = 0.0001):
"""
Creates an edge that has the reverse direction of the input edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The reversed edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Reverse - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
return Edge.ByVertices([edge.EndVertex(), edge.StartVertex()], tolerance=tolerance)
@staticmethod
def SetLength(edge , length: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001):
"""
Returns an edge with the new length in the same direction as the input edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
length : float , optional
The desired length of the edge. The default is 1.
bothSides : bool , optional
If set to True, the edge will be offset symmetrically from each end. The default is True.
reverse : bool , optional
If set to True, the edge will be offset from its start vertex. Otherwise, it will be offset from its end vertex. The default is False.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The extended edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.SetLength - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
distance = (length - Edge.Length(edge))
if distance > 0:
return Edge.Extend(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance)
return Edge.Trim(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance)
@staticmethod
def StartVertex(edge):
"""
Returns the start vertex of the input edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
Returns
-------
topologic_core.Vertex
The start vertex of the input edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.StartVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
vert = None
try:
vert = edge.StartVertex()
except:
vert = None
return vert
@staticmethod
def Trim(edge, distance: float = 0.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001):
"""
Trims the input edge by the input distance.
Parameters
----------
edge : topologic_core.Edge
The input edge.
distance : float , optional
The offset distance. The default is 0.
bothSides : bool , optional
If set to True, the edge will be trimmed by half the distance at each end. The default is False.
reverse : bool , optional
If set to True, the edge will be trimmed from its start vertex. Otherwise, it will be trimmed from its end vertex. The default is False.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The trimmed edge.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Trim - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
distance = abs(distance)
if distance == 0:
return edge
if distance < tolerance:
print("Edge.Trim - Warning: The input distance parameter is less than the input tolerance parameter. Returning the input edge.")
return edge
sv = Edge.StartVertex(edge)
ev = Edge.EndVertex(edge)
if bothSides:
sve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=sv, tolerance=tolerance)
eve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=ev, tolerance=tolerance)
elif reverse:
sve = Edge.VertexByDistance(edge, distance=distance, origin=sv, tolerance=tolerance)
eve = Edge.EndVertex(edge)
else:
sve = Edge.StartVertex(edge)
eve = Edge.VertexByDistance(edge, distance=-distance, origin=ev, tolerance=tolerance)
return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
@staticmethod
def TrimByEdge2D(edgeA, edgeB, reverse: bool = False, tolerance: float = 0.0001):
"""
Trims the first input edge by the second input edge. This works only in the XY plane. Z coordinates are ignored.
Parameters
----------
edgeA : topologic_core.Edge
The first input edge.
edgeB : topologic_core.Edge
The second input edge.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Edge
The trimmed edge.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Topology import Topology
if not Topology.IsInstance(edgeA, "Edge"):
print("Edge.TrimByEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.")
return None
if not Topology.IsInstance(edgeB, "Edge"):
print("Edge.TrimByEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.")
return None
sva = Edge.StartVertex(edgeA)
eva = Edge.EndVertex(edgeA)
intVertex = Edge.Intersect2D(edgeA, edgeB)
if intVertex and (Vertex.IsInternal(intVertex, edgeA)):
if reverse:
return Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True)
else:
return Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True)
return edgeA
@staticmethod
def VertexByDistance(edge, distance: float = 0.0, origin= None, tolerance: float = 0.0001):
"""
Creates a vertex along the input edge offset by the input distance from the input origin.
Parameters
----------
edge : topologic_core.Edge
The input edge.
distance : float , optional
The offset distance. The default is 0.
origin : topologic_core.Vertex , optional
The origin of the offset distance. If set to None, the origin will be set to the start vertex of the input edge. The default is None.
tolerance : float , optional
The desired tolerance. The default is 0.0001.
Returns
-------
topologic_core.Vertex
The created vertex.
"""
from topologicpy.Vertex import Vertex
from topologicpy.Vector import Vector
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.TrimByEdge2D - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
if not origin:
origin = edge.StartVertex()
if not Topology.IsInstance(origin, "Vertex"):
print("Edge.TrimByEdge2D - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
return None
sv = edge.StartVertex()
ev = edge.EndVertex()
vx = ev.X() - sv.X()
vy = ev.Y() - sv.Y()
vz = ev.Z() - sv.Z()
vector = Vector.Normalize([vx, vy, vz])
vector = Vector.Multiply(vector, distance, tolerance)
return Vertex.ByCoordinates(origin.X()+vector[0], origin.Y()+vector[1], origin.Z()+vector[2])
@staticmethod
def VertexByParameter(edge, u: float = 0.0):
"""
Creates a vertex along the input edge offset by the input *u* parameter.
Parameters
----------
edge : topologic_core.Edge
The input edge.
u : float , optional
The *u* parameter along the input topologic Edge. A parameter of 0 returns the start vertex. A parameter of 1 returns the end vertex. The default is 0.
Returns
-------
topologic_core.Vertex
The created vertex.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.VertexByParameter - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
vertex = None
if u == 0:
vertex = edge.StartVertex()
elif u == 1:
vertex = edge.EndVertex()
else:
dir = Edge.Direction(edge)
edge_length = Edge.Length(edge)
dist = edge_length*u
vertex = Topology.TranslateByDirectionDistance(Edge.StartVertex(edge), direction=dir, distance=dist)
return vertex
@staticmethod
def Vertices(edge) -> list:
"""
Returns the list of vertices of the input edge.
Parameters
----------
edge : topologic_core.Edge
The input edge.
Returns
-------
list
The list of vertices.
"""
from topologicpy.Topology import Topology
if not Topology.IsInstance(edge, "Edge"):
print("Edge.Vertices - Error: The input edge parameter is not a valid topologic edge. Returning None.")
return None
vertices = []
_ = edge.Vertices(None, vertices) # Hook to Core
return vertices
Classes
class Edge
-
Expand source code
class Edge(): @staticmethod def Angle(edgeA, edgeB, mantissa: int = 6, bracket: bool = False) -> float: """ Returns the angle in degrees between the two input edges. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic Edge The second input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. bracket : bool If set to True, the returned angle is bracketed between 0 and 180. The default is False. Returns ------- float The angle in degrees between the two input edges. """ from topologicpy.Topology import Topology from topologicpy.Vector import Vector if not Topology.IsInstance(edgeA, "Edge"): print("Edge.Angle - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.Angle - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None dirA = Edge.Direction(edgeA, mantissa) dirB = Edge.Direction(edgeB, mantissa) ang = Vector.Angle(dirA, dirB) if bracket: if ang > 90: ang = 180 - ang return round(ang, mantissa) @staticmethod def Bisect(edgeA, edgeB, length: float = 1.0, placement: int = 0, tolerance: float = 0.0001): """ Creates a bisecting edge between edgeA and edgeB. Parameters ---------- edgeA : topologic_core.Edge The first topologic Edge. edgeB : topologic Edge The second topologic Edge. length : float , optional The desired length of the bisecting edge. The default is 1.0. placement : int , optional The desired placement of the bisecting edge. If set to 0, the bisecting edge centroid will be placed at the end vertex of the first edge. If set to 1, the bisecting edge start vertex will be placed at the end vertex of the first edge. If set to 2, the bisecting edge end vertex will be placed at the end vertex of the first edge. If set to any number other than 0, 1, or 2, the bisecting edge centroid will be placed at the end vertex of the first edge. The default is 0. tolerance : float , optional The desired tolerance to decide if an Edge can be created. The default is 0.0001. Returns ------- topologic_core.Edge The created bisecting edge. """ import numpy as np from topologicpy.Wire import Wire from topologicpy.Cluster import Cluster from topologicpy.Topology import Topology from topologicpy.Vector import Vector if not Topology.IsInstance(edgeA, "Edge"): print("Edge.Bisect - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.Bisect - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None if Edge.Length(edgeA) < tolerance: print("Edge.Bisect - Error: The input edgeA parameter is shorter than the input tolerance parameter. Returning None.") return None if Edge.Length(edgeB) < tolerance: print("Edge.Bisect - Error: The input edgeB parameter is shorter than the input tolerance parameter. Returning None.") return None wire = Topology.SelfMerge(Cluster.ByTopologies([edgeA, edgeB]), tolerance=tolerance) if not Topology.IsInstance(wire, "Wire"): print("Edge.Bisect - Error: The input edgeA and edgeB parameters do not share a vertex and thus cannot be bisected. Returning None.") return None edges = Topology.Edges(wire) edgeA = edges[0] edgeB = edges[1] sv = Wire.Vertices(wire)[1] dirA = Edge.Direction(edgeA) dirB = Edge.Direction(edgeB) bisecting_vector = Vector.Bisect(dirA, dirB) ev = Topology.TranslateByDirectionDistance(sv, bisecting_vector, length) bisecting_edge = Edge.ByVertices([sv, ev]) return bisecting_edge @staticmethod def ByFaceNormal(face, origin= None, length: float = 1.0, tolerance: float = 0.0001): """ Creates a straight edge representing the normal to the input face. Parameters ---------- face : topologic_core.Face The input face origin : toopologic.Vertex , optional The desired origin of the edge. If set to None, the centroid of the face is chosen as the origin of the edge. The default is None. length : float , optional The desired length of the edge. The default is 1. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- edge : topologic_core.Edge The created edge. """ from topologicpy.Vertex import Vertex from topologicpy.Face import Face from topologicpy.Topology import Topology edge = None if not Topology.IsInstance(face, "Face"): print("Edge.ByFaceNormal - Error: The input face parameter is not a valid topologic face. Returning None.") return None if not Topology.IsInstance(origin, "Vertex"): origin = Topology.Centroid(face) if not Topology.IsInstance(origin, "Vertex"): print("Edge.ByFaceNormal - Error: The input origin parameter is not a valid topologic origin. Returning None.") return None n = Face.Normal(face) v2 = Topology.Translate(origin, n[0], n[1], n[2]) edge = Edge.ByStartVertexEndVertex(origin, v2, tolerance=tolerance, silent=True) if not Topology.IsInstance(edge, "Edge"): print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.") return None edge = Edge.SetLength(edge, length, bothSides=False) if not Topology.IsInstance(edge, "Edge"): print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.") return None return edge @staticmethod def ByOffset2D(edge, offset: float = 1.0, tolerance: float = 0.0001): """ Creates and edge offset from the input edge. This method is intended for edges that are in the XY plane. Parameters ---------- edge : topologic_core.Edge The input edge. offset : float , optional The desired offset. The default is 1. tolerance : float , optiona The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge An edge offset from the input edge. """ from topologicpy.Topology import Topology from topologicpy.Vector import Vector n = Edge.Normal(edge) n = Vector.Normalize(n) n = Vector.Multiply(n, offset, tolerance) edge = Topology.Translate(edge, n[0], n[1], n[2]) return edge @staticmethod def ByStartVertexEndVertex(vertexA, vertexB, tolerance: float = 0.0001, silent=False): """ Creates a straight edge that connects the input vertices. Parameters ---------- vertexA : topologic_core.Vertex The first input vertex. This is considered the start vertex. vertexB : toopologic.Vertex The second input vertex. This is considered the end vertex. tolerance : float , optional The desired tolerance to decide if an Edge can be created. The default is 0.0001. silent : bool , optional If set to False, error and warning messages are printed. Otherwise, they are not. The default is False. Returns ------- edge : topologic_core.Edge The created edge. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology edge = None if not Topology.IsInstance(vertexA, "Vertex"): if not silent: print("Edge.ByStartVertexEndVertex - Error: The input vertexA parameter is not a valid topologic vertex. Returning None.") return None if not Topology.IsInstance(vertexB, "Vertex"): if not silent: print("Edge.ByStartVertexEndVertex - Error: The input vertexB parameter is not a valid topologic vertex. Returning None.") return None if Topology.IsSame(vertexA, vertexB): if not silent: print("Edge.ByStartVertexEndVertex - Error: The input vertexA and vertexB parameters are the same vertex. Returning None.") return None if Vertex.Distance(vertexA, vertexB) < tolerance: if not silent: print("Edge.ByStartVertexEndVertex - Error: The distance between the input vertexA and vertexB parameters is less than the input tolerance. Returning None.") return None try: edge = topologic.Edge.ByStartVertexEndVertex(vertexA, vertexB) # Hook to Core except: if not silent: print("Edge.ByStartVertexEndVertex - Error: Could not create an edge. Returning None.") edge = None return edge @staticmethod def ByVertices(*args, tolerance: float = 0.0001, silent: bool = False): """ Creates a straight edge that connects the input list of vertices. Parameters ---------- vertices : list The input list of vertices. The first item is considered the start vertex and the last item is considered the end vertex. tolerance : float , optional The desired tolerance to decide if an edge can be created. The default is 0.0001. silent : bool , optional If set to True, error and warning messages are printed. Otherwise, they are not. The default is True. Returns ------- topologic_core.Edge The created edge. """ from topologicpy.Helper import Helper from topologicpy.Topology import Topology if len(args) == 0: print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.") return None if len(args) == 1: vertices = args[0] if isinstance(vertices, list): if len(vertices) == 0: if not silent: print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.") return None else: vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")] if len(vertexList) == 0: if not silent: print("Edge.ByVertices - Error: The input vertices parameter does not contain any valid vertices. Returning None.") return None else: if not silent: print("Edge.ByVertices - Warning: The input vertices parameter contains only one vertex. Returning None.") return None else: vertexList = Helper.Flatten(list(args)) vertexList = [x for x in vertexList if Topology.IsInstance(x, "Vertex")] if len(vertexList) < 2: if not silent: print("Edge.ByVertices - Error: The input vertices parameter has less than two vertices. Returning None.") return None return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance, silent=silent) @staticmethod def ByVerticesCluster(cluster, tolerance: float = 0.0001): """ Creates a straight edge that connects the input cluster of vertices. Parameters ---------- cluster : topologic_core.Cluster The input cluster of vertices. The first item is considered the start vertex and the last item is considered the end vertex. tolerance : float , optional The desired tolerance to decide if an edge can be created. The default is 0.0001. Returns ------- topologic_core.Edge The created edge. """ from topologicpy.Cluster import Cluster from topologicpy.Topology import Topology if not Topology.IsInstance(cluster, "Cluster"): print("Edge.ByVerticesCluster - Error: The input cluster parameter is not a valid topologic cluster. Returning None.") return None vertices = Cluster.Vertices(cluster) vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")] if len(vertexList) < 2: print("Edge.ByVerticesCluster - Error: The input cluster parameter contains less than two vertices. Returning None.") return None return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance) @staticmethod def Direction(edge, mantissa: int = 6) -> list: """ Returns the direction of the input edge expressed as a list of three numbers. Parameters ---------- edge : topologic_core.Edge The input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. Returns ------- list The direction of the input edge. """ from topologicpy.Vector import Vector from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Direction - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None ev = edge.EndVertex() sv = edge.StartVertex() x = ev.X() - sv.X() y = ev.Y() - sv.Y() z = ev.Z() - sv.Z() uvec = Vector.Normalize([x,y,z]) x = round(uvec[0], mantissa) y = round(uvec[1], mantissa) z = round(uvec[2], mantissa) return [x, y, z] @staticmethod def EndVertex(edge): """ Returns the end vertex of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. Returns ------- topologic_core.Vertex The end vertex of the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.EndVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vert = None try: vert = edge.EndVertex() except: vert = None return vert @staticmethod def Extend(edge, distance: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001): """ Extends the input edge by the input distance. Parameters ---------- edge : topologic_core.Edge The input edge. distance : float , optional The offset distance. The default is 1. bothSides : bool , optional If set to True, the edge will be extended by half the distance at each end. The default is False. reverse : bool , optional If set to True, the edge will be extended from its start vertex. Otherwise, it will be extended from its end vertex. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The extended edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Extend - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None distance = abs(distance) if distance < tolerance: return edge sv = Edge.StartVertex(edge) ev = Edge.EndVertex(edge) if bothSides: sve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=sv, tolerance=tolerance) eve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=ev, tolerance=tolerance) elif reverse: sve = Edge.VertexByDistance(edge, distance=-distance, origin=sv, tolerance=tolerance) eve = Edge.EndVertex(edge) else: sve = Edge.StartVertex(edge) eve = Edge.VertexByDistance(edge, distance=distance, origin=ev, tolerance=tolerance) return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True) @staticmethod def ExtendToEdge2D(edgeA, edgeB, tolerance: float = 0.0001): """ Extends the first input edge to meet the second input edge. This works only in the XY plane. Z coordinates are ignored. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The extended edge. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): print("Edge.ExtendToEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.ExtendToEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None sva = Edge.StartVertex(edgeA) eva = Edge.EndVertex(edgeA) intVertex = Edge.Intersect2D(edgeA, edgeB) if intVertex and not (Vertex.IsInternal(intVertex, edgeA)): e1 = Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True) e2 = Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True) l1 = Edge.Length(e1) l2 = Edge.Length(e2) if l1 > l2: return e1 else: return e2 print("Edge.ExtendToEdge2D - Error: The operation failed. Returning None.") return None @staticmethod def Index(edge, edges: list, strict: bool = False, tolerance: float = 0.0001) -> int: """ Returns index of the input edge in the input list of edges Parameters ---------- edge : topologic_core.Edge The input edge. edges : list The input list of edges. strict : bool , optional If set to True, the edge must be strictly identical to the one found in the list. Otherwise, a distance comparison is used. The default is False. tolerance : float , optional The tolerance for computing if the input edge is identical to an edge from the list. The default is 0.0001. Returns ------- int The index of the input edge in the input list of edges. """ from topologicpy.Topology import Topology from topologicpy.Vertex import Vertex if not Topology.IsInstance(edge, "Edge"): print("Edge.Index - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not isinstance(edges, list): print("Edge.Index - Error: The input edges parameter is not a valid list. Returning None.") return None edges = [e for e in edges if Topology.IsInstance(e, "Edge")] if len(edges) < 1: print("Edge.Index - Error: The input edges parameter contains no valid edges. Returning None.") return None sva = Edge.StartVertex(edge) eva = Edge.EndVertex(edge) for i in range(len(edges)): if strict: if Topology.IsSame(edge, edges[i]): return i else: svb = Edge.StartVertex(edges[i]) evb = Edge.EndVertex(edges[i]) dsvsv = Vertex.Distance(sva, svb) devev = Vertex.Distance(eva, evb) if dsvsv < tolerance and devev < tolerance: return i dsvev = Vertex.Distance(sva, evb) devsv = Vertex.Distance(eva, svb) if dsvev < tolerance and devsv < tolerance: return i return None @staticmethod def Intersect2D(edgeA, edgeB, silent: bool = False): """ Returns the intersection of the two input edges as a topologic_core.Vertex. This works only in the XY plane. Z coordinates are ignored. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. silent : bool , optional If set to False, error and warning messages are displayed. Otherwise they are not. The default is False. Returns ------- topologic_core.Vertex The intersection of the two input edges. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): if not silent: print("Edge.Intersect2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): if not silent: print("Edge.Intersect2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None sva = Edge.StartVertex(edgeA) eva = Edge.EndVertex(edgeA) svb = Edge.StartVertex(edgeB) evb = Edge.EndVertex(edgeB) # Line AB represented as a1x + b1y = c1 a1 = Vertex.Y(eva) - Vertex.Y(sva) b1 = Vertex.X(sva) - Vertex.X(eva) c1 = a1*(Vertex.X(sva)) + b1*(Vertex.Y(sva)) # Line CD represented as a2x + b2y = c2 a2 = Vertex.Y(evb) - Vertex.Y(svb) b2 = Vertex.X(svb) - Vertex.X(evb) c2 = a2*(Vertex.X(svb)) + b2*(Vertex.Y(svb)) determinant = a1*b2 - a2*b1 if (determinant == 0): # The lines are parallel. This is simplified # by returning a pair of FLT_MAX if not silent: print("Edge.Intersect2D - Warning: The input edgeA and edgeB parameters are parallel edges. Returning None.") return None else: x = (b2*c1 - b1*c2)/determinant y = (a1*c2 - a2*c1)/determinant return Vertex.ByCoordinates(x,y,0) @staticmethod def IsCollinear(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001) -> bool: """ Return True if the two input edges are collinear. Returns False otherwise. This code is based on a contribution by https://github.com/gaoxipeng Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- bool True if the two edges are collinear. False otherwise. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology import numpy as np if not Topology.IsInstance(edgeA, "Edge"): print("Edge.IsCollinear - Error: The input parameter edgeA is not a valid edge. Returning None") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.IsCollinear - Error: The input parameter edgeB is not a valid edge. Returning None") return None if Edge.Length(edgeA) < tolerance: print("Edge.IsCollinear - Error: The length of edgeA is less than the tolerance. Returning None") return None if Edge.Length(edgeB) < tolerance: print("Edge.IsCollinear - Error: The length of edgeB is less than the tolerance. Returning None") return None # Get start and end points of the first edge start_a = Edge.StartVertex(edgeA) end_a = Edge.EndVertex(edgeA) start_a_coords = np.array([Vertex.X(start_a), Vertex.Y(start_a), Vertex.Z(start_a)]) end_a_coords = np.array( [Vertex.X(end_a, mantissa=mantissa), Vertex.Y(end_a, mantissa=mantissa), Vertex.Z(end_a, mantissa=mantissa)]) # Calculate the direction vector of the first edge direction_a = end_a_coords - start_a_coords # Normalize the direction vector norm_a = np.linalg.norm(direction_a) if norm_a == 0: print("Edge.IsCollinear - Error: Division by zero. Returning None.") return None direction_a /= norm_a # Function to calculate perpendicular distance from a point to the line defined by a point and direction vector def distance_from_line(point, line_point, line_dir): point = np.array([Vertex.X(point, mantissa=mantissa), Vertex.Y(point, mantissa=mantissa), Vertex.Z(point, mantissa=mantissa)]) line_point = np.array(line_point) diff = point - line_point cross_product = np.cross(diff, line_dir) line_dir_norm = np.linalg.norm(line_dir) if line_dir_norm == 0: print("Edge.IsCollinear - Error: Division by zero. Returning None.") return None distance = np.linalg.norm(cross_product) / np.linalg.norm(line_dir) return distance # Get start and end points of the second edge start_b = Edge.StartVertex(edgeB) end_b = Edge.EndVertex(edgeB) # Calculate distances for start and end vertices of the second edge to the line defined by the first edge distance_start = distance_from_line(start_b, start_a_coords, direction_a) distance_end = distance_from_line(end_b, start_a_coords, direction_a) # Check if both distances are within tolerance return bool(distance_start < tolerance) and bool(distance_end < tolerance) @staticmethod def IsParallel(edgeA, edgeB, mantissa: int = 6, angTolerance: float = 0.1) -> bool: """ Return True if the two input edges are parallel. Returns False otherwise. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. angTolerance : float , optional The angular tolerance used for the test. The default is 0.1. Returns ------- bool True if the two edges are collinear. False otherwise. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): print("Edge.IsParallel - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.IsParallel - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True) if abs(ang) < angTolerance or abs(180 - ang) < angTolerance: return True return False @staticmethod def Length(edge, mantissa: int = 6) -> float: """ Returns the length of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. Returns ------- float The length of the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Length - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None length = None try: length = round(topologic.EdgeUtility.Length(edge), mantissa) # Hook to Core except: length = None if length == None: print("Edge.Length - Error: Could not compute the length of the input edge parameter. Returning None.") return length @staticmethod def Line(origin= None, length: float = 1, direction: list = [1,0,0], placement: str ="center", tolerance: float = 0.0001): """ Creates a straight edge (line) using the input parameters. Parameters ---------- origin : topologic_core.Vertex , optional The origin location of the box. The default is None which results in the edge being placed at (0, 0, 0). length : float , optional The desired length of the edge. The default is 1.0. direction : list , optional The desired direction (vector) of the edge. The default is [1,0,0] (along the X-axis). placement : str , optional The desired placement of the edge. The options are: 1. "center" which places the center of the edge at the origin. 2. "start" which places the start of the edge at the origin. 3. "end" which places the end of the edge at the origin. The default is "center". tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The created edge """ from topologicpy.Vertex import Vertex from topologicpy.Vector import Vector from topologicpy.Topology import Topology if origin == None: origin = Vertex.Origin() if not Topology.IsInstance(origin, "Vertex"): print("Edge.Line - Error: The input origin parameter is not a valid topologic vertex. Returning None.") return None if length <= 0: print("Edge.Line - Error: The input length is less than or equal to zero. Returning None.") return None if not isinstance(direction, list): print("Edge.Line - Error: The input direction parameter is not a valid list. Returning None.") return None if not len(direction) == 3: print("Edge.Line - Error: The length of the input direction parameter is not equal to three. Returning None.") return None direction = Vector.Normalize(direction) if "center" in placement.lower(): sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length*0.5) ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length) return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True) if "start" in placement.lower(): sv = origin ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length) return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True) if "end" in placement.lower(): sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length) ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length) return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True) else: print("Edge.Line - Error: The input placement string is not one of center, start, or end. Returning None.") return None @staticmethod def Normal(edge, angle: float = 0.0): """ Returns the normal (perpendicular) vector to the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. angle : float , optional The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge by the angle value around the axis defined by the input edge. The default is 0.0. Returns ------- list The normal (perpendicular ) vector to the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Normal - Error: The input edge parameter is not a valid edge. Returning None.") return None normal_edge = Edge.NormalAsEdge(edge, length=1.0, u=0.5, angle=angle) return Edge.Direction(normal_edge) @staticmethod def NormalAsEdge(edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0): """ Returns the normal (perpendicular) vector to the input edge as an edge. Parameters ---------- edge : topologic_core.Edge The input edge. length : float , optional The desired length of the normal edge. The default is 1.0. u : float , optional The desired u parameter placement of the normal edge. A value of 0.0 places the normal edge at the start vertex of the input edge, a value of 0.5 places the normal edge at the midpoint of the input edge, and a value of 1.0 places the normal edge at the end vertex of the input edge. The default is 0.5 angle : float , optional The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge by the angle value around the axis defined by the input edge. The default is 0.0. Returns ------- topologic_core.Edge The normal (perpendicular) vector to the input edge as an edge. """ import numpy as np from numpy.linalg import norm import topologic_core as topologic from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology def calculate_normal(start_vertex, end_vertex): start_vertex = [float(x) for x in start_vertex] end_vertex = [float(x) for x in end_vertex] # Calculate the direction vector of the line segment direction_vector = np.array(end_vertex) - np.array(start_vertex) # Calculate the normal vector by swapping components and negating one of them normal_vector = np.array([-direction_vector[1], direction_vector[0], 0]) # Normalize the normal vector normal_vector /= norm(normal_vector) return normal_vector def calculate_normal_line(start_vertex, end_vertex): # Calculate the normal vector of the line normal_vector = calculate_normal(start_vertex, end_vertex) # Calculate the new end vertex for the normal line to have a length of 1 normal_end_vertex = np.array(start_vertex) + normal_vector # Return the start and end vertices of the normal line return start_vertex, list(normal_end_vertex) if not Topology.IsInstance(edge, "Edge"): print("Edge.NormalAsEdge - Error: The input edge parameter is not a valid edge. Returning None.") return None if length <= 0.0: print("Edge.NormalAsEdge - Error: The input length parameter is not a positive number greater than zero. Returning None.") return None edge_direction = Edge.Direction(edge) x, y, z = edge_direction start_vertex = Vertex.Coordinates(Edge.StartVertex(edge)) end_vertex = Vertex.Coordinates(Edge.EndVertex(edge)) normal_line_start, normal_line_end = calculate_normal_line(start_vertex, end_vertex) sv = Vertex.ByCoordinates(normal_line_start) ev = Vertex.ByCoordinates(list(normal_line_end)) normal_edge = Edge.ByVertices([sv, ev]) normal_edge = Edge.SetLength(normal_edge, length, bothSides=False) normal_edge = Topology.Rotate(normal_edge, origin=Edge.StartVertex(normal_edge), axis=[x,y,z], angle=angle) dist = Edge.Length(edge)*u normal_edge = Topology.TranslateByDirectionDistance(normal_edge, edge_direction, dist) return normal_edge @staticmethod def Normalize(edge, useEndVertex: bool = False, tolerance: float = 0.0001): """ Creates a normalized edge that has the same direction as the input edge, but a length of 1. Parameters ---------- edge : topologic_core.Edge The input edge. useEndVertex : bool , optional If True the normalized edge end vertex will be placed at the end vertex of the input edge. Otherwise, the normalized edge start vertex will be placed at the start vertex of the input edge. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The normalized edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Normalize - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not useEndVertex: sv = edge.StartVertex() ev = Edge.VertexByDistance(edge, 1.0, edge.StartVertex()) else: sv = Edge.VertexByDistance(edge, 1.0, edge.StartVertex()) ev = edge.EndVertex() return Edge.ByVertices([sv, ev], tolerance=tolerance) @staticmethod def ParameterAtVertex(edge, vertex, mantissa: int = 6, silent: bool = False) -> float: """ Returns the *u* parameter along the input edge based on the location of the input vertex. Parameters ---------- edge : topologic_core.Edge The input edge. vertex : topologic_core.Vertex The input vertex. mantissa : int , optional The desired length of the mantissa. The default is 6. silent : bool , optional If set to False, error and warning messages are printed. Otherwise, they are not. The default is False. Returns ------- float The *u* parameter along the input edge based on the location of the input vertex. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): if not silent: print("Edge.ParameterAtVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(vertex, "Vertex"): if not silent: print("Edge.ParameterAtVertex - Error: The input vertex parameter is not a valid topologic vertex. Returning None.") return None parameter = None try: parameter = topologic.EdgeUtility.ParameterAtPoint(edge, vertex) # Hook to Core except: return None #Return silently because topologic C++ returns a runtime error if point is not on curve. return round(parameter, mantissa) @staticmethod def Reverse(edge, tolerance: float = 0.0001): """ Creates an edge that has the reverse direction of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The reversed edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Reverse - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None return Edge.ByVertices([edge.EndVertex(), edge.StartVertex()], tolerance=tolerance) @staticmethod def SetLength(edge , length: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001): """ Returns an edge with the new length in the same direction as the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. length : float , optional The desired length of the edge. The default is 1. bothSides : bool , optional If set to True, the edge will be offset symmetrically from each end. The default is True. reverse : bool , optional If set to True, the edge will be offset from its start vertex. Otherwise, it will be offset from its end vertex. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The extended edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.SetLength - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None distance = (length - Edge.Length(edge)) if distance > 0: return Edge.Extend(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance) return Edge.Trim(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance) @staticmethod def StartVertex(edge): """ Returns the start vertex of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. Returns ------- topologic_core.Vertex The start vertex of the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.StartVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vert = None try: vert = edge.StartVertex() except: vert = None return vert @staticmethod def Trim(edge, distance: float = 0.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001): """ Trims the input edge by the input distance. Parameters ---------- edge : topologic_core.Edge The input edge. distance : float , optional The offset distance. The default is 0. bothSides : bool , optional If set to True, the edge will be trimmed by half the distance at each end. The default is False. reverse : bool , optional If set to True, the edge will be trimmed from its start vertex. Otherwise, it will be trimmed from its end vertex. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The trimmed edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Trim - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None distance = abs(distance) if distance == 0: return edge if distance < tolerance: print("Edge.Trim - Warning: The input distance parameter is less than the input tolerance parameter. Returning the input edge.") return edge sv = Edge.StartVertex(edge) ev = Edge.EndVertex(edge) if bothSides: sve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=sv, tolerance=tolerance) eve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=ev, tolerance=tolerance) elif reverse: sve = Edge.VertexByDistance(edge, distance=distance, origin=sv, tolerance=tolerance) eve = Edge.EndVertex(edge) else: sve = Edge.StartVertex(edge) eve = Edge.VertexByDistance(edge, distance=-distance, origin=ev, tolerance=tolerance) return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True) @staticmethod def TrimByEdge2D(edgeA, edgeB, reverse: bool = False, tolerance: float = 0.0001): """ Trims the first input edge by the second input edge. This works only in the XY plane. Z coordinates are ignored. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The trimmed edge. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): print("Edge.TrimByEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.TrimByEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None sva = Edge.StartVertex(edgeA) eva = Edge.EndVertex(edgeA) intVertex = Edge.Intersect2D(edgeA, edgeB) if intVertex and (Vertex.IsInternal(intVertex, edgeA)): if reverse: return Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True) else: return Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True) return edgeA @staticmethod def VertexByDistance(edge, distance: float = 0.0, origin= None, tolerance: float = 0.0001): """ Creates a vertex along the input edge offset by the input distance from the input origin. Parameters ---------- edge : topologic_core.Edge The input edge. distance : float , optional The offset distance. The default is 0. origin : topologic_core.Vertex , optional The origin of the offset distance. If set to None, the origin will be set to the start vertex of the input edge. The default is None. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Vertex The created vertex. """ from topologicpy.Vertex import Vertex from topologicpy.Vector import Vector from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.TrimByEdge2D - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not origin: origin = edge.StartVertex() if not Topology.IsInstance(origin, "Vertex"): print("Edge.TrimByEdge2D - Error: The input origin parameter is not a valid topologic vertex. Returning None.") return None sv = edge.StartVertex() ev = edge.EndVertex() vx = ev.X() - sv.X() vy = ev.Y() - sv.Y() vz = ev.Z() - sv.Z() vector = Vector.Normalize([vx, vy, vz]) vector = Vector.Multiply(vector, distance, tolerance) return Vertex.ByCoordinates(origin.X()+vector[0], origin.Y()+vector[1], origin.Z()+vector[2]) @staticmethod def VertexByParameter(edge, u: float = 0.0): """ Creates a vertex along the input edge offset by the input *u* parameter. Parameters ---------- edge : topologic_core.Edge The input edge. u : float , optional The *u* parameter along the input topologic Edge. A parameter of 0 returns the start vertex. A parameter of 1 returns the end vertex. The default is 0. Returns ------- topologic_core.Vertex The created vertex. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.VertexByParameter - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vertex = None if u == 0: vertex = edge.StartVertex() elif u == 1: vertex = edge.EndVertex() else: dir = Edge.Direction(edge) edge_length = Edge.Length(edge) dist = edge_length*u vertex = Topology.TranslateByDirectionDistance(Edge.StartVertex(edge), direction=dir, distance=dist) return vertex @staticmethod def Vertices(edge) -> list: """ Returns the list of vertices of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. Returns ------- list The list of vertices. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Vertices - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vertices = [] _ = edge.Vertices(None, vertices) # Hook to Core return vertices
Static methods
def Angle(edgeA, edgeB, mantissa: int = 6, bracket: bool = False) ‑> float
-
Returns the angle in degrees between the two input edges.
Parameters
edgeA
:topologic_core.Edge
- The first input edge.
edgeB
:topologic Edge
- The second input edge.
mantissa
:int
, optional- The desired length of the mantissa. The default is 6.
bracket
:bool
- If set to True, the returned angle is bracketed between 0 and 180. The default is False.
Returns
float
- The angle in degrees between the two input edges.
Expand source code
@staticmethod def Angle(edgeA, edgeB, mantissa: int = 6, bracket: bool = False) -> float: """ Returns the angle in degrees between the two input edges. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic Edge The second input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. bracket : bool If set to True, the returned angle is bracketed between 0 and 180. The default is False. Returns ------- float The angle in degrees between the two input edges. """ from topologicpy.Topology import Topology from topologicpy.Vector import Vector if not Topology.IsInstance(edgeA, "Edge"): print("Edge.Angle - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.Angle - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None dirA = Edge.Direction(edgeA, mantissa) dirB = Edge.Direction(edgeB, mantissa) ang = Vector.Angle(dirA, dirB) if bracket: if ang > 90: ang = 180 - ang return round(ang, mantissa)
def Bisect(edgeA, edgeB, length: float = 1.0, placement: int = 0, tolerance: float = 0.0001)
-
Creates a bisecting edge between edgeA and edgeB.
Parameters
edgeA
:topologic_core.Edge
- The first topologic Edge.
edgeB
:topologic Edge
- The second topologic Edge.
length
:float
, optional- The desired length of the bisecting edge. The default is 1.0.
placement
:int
, optional- The desired placement of the bisecting edge. If set to 0, the bisecting edge centroid will be placed at the end vertex of the first edge. If set to 1, the bisecting edge start vertex will be placed at the end vertex of the first edge. If set to 2, the bisecting edge end vertex will be placed at the end vertex of the first edge. If set to any number other than 0, 1, or 2, the bisecting edge centroid will be placed at the end vertex of the first edge. The default is 0.
tolerance
:float
, optional- The desired tolerance to decide if an Edge can be created. The default is 0.0001.
Returns
topologic_core.Edge
- The created bisecting edge.
Expand source code
@staticmethod def Bisect(edgeA, edgeB, length: float = 1.0, placement: int = 0, tolerance: float = 0.0001): """ Creates a bisecting edge between edgeA and edgeB. Parameters ---------- edgeA : topologic_core.Edge The first topologic Edge. edgeB : topologic Edge The second topologic Edge. length : float , optional The desired length of the bisecting edge. The default is 1.0. placement : int , optional The desired placement of the bisecting edge. If set to 0, the bisecting edge centroid will be placed at the end vertex of the first edge. If set to 1, the bisecting edge start vertex will be placed at the end vertex of the first edge. If set to 2, the bisecting edge end vertex will be placed at the end vertex of the first edge. If set to any number other than 0, 1, or 2, the bisecting edge centroid will be placed at the end vertex of the first edge. The default is 0. tolerance : float , optional The desired tolerance to decide if an Edge can be created. The default is 0.0001. Returns ------- topologic_core.Edge The created bisecting edge. """ import numpy as np from topologicpy.Wire import Wire from topologicpy.Cluster import Cluster from topologicpy.Topology import Topology from topologicpy.Vector import Vector if not Topology.IsInstance(edgeA, "Edge"): print("Edge.Bisect - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.Bisect - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None if Edge.Length(edgeA) < tolerance: print("Edge.Bisect - Error: The input edgeA parameter is shorter than the input tolerance parameter. Returning None.") return None if Edge.Length(edgeB) < tolerance: print("Edge.Bisect - Error: The input edgeB parameter is shorter than the input tolerance parameter. Returning None.") return None wire = Topology.SelfMerge(Cluster.ByTopologies([edgeA, edgeB]), tolerance=tolerance) if not Topology.IsInstance(wire, "Wire"): print("Edge.Bisect - Error: The input edgeA and edgeB parameters do not share a vertex and thus cannot be bisected. Returning None.") return None edges = Topology.Edges(wire) edgeA = edges[0] edgeB = edges[1] sv = Wire.Vertices(wire)[1] dirA = Edge.Direction(edgeA) dirB = Edge.Direction(edgeB) bisecting_vector = Vector.Bisect(dirA, dirB) ev = Topology.TranslateByDirectionDistance(sv, bisecting_vector, length) bisecting_edge = Edge.ByVertices([sv, ev]) return bisecting_edge
def ByFaceNormal(face, origin=None, length: float = 1.0, tolerance: float = 0.0001)
-
Creates a straight edge representing the normal to the input face.
Parameters
face
:topologic_core.Face
- The input face
origin
:toopologic.Vertex
, optional- The desired origin of the edge. If set to None, the centroid of the face is chosen as the origin of the edge. The default is None.
length
:float
, optional- The desired length of the edge. The default is 1.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
edge
:topologic_core.Edge
- The created edge.
Expand source code
@staticmethod def ByFaceNormal(face, origin= None, length: float = 1.0, tolerance: float = 0.0001): """ Creates a straight edge representing the normal to the input face. Parameters ---------- face : topologic_core.Face The input face origin : toopologic.Vertex , optional The desired origin of the edge. If set to None, the centroid of the face is chosen as the origin of the edge. The default is None. length : float , optional The desired length of the edge. The default is 1. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- edge : topologic_core.Edge The created edge. """ from topologicpy.Vertex import Vertex from topologicpy.Face import Face from topologicpy.Topology import Topology edge = None if not Topology.IsInstance(face, "Face"): print("Edge.ByFaceNormal - Error: The input face parameter is not a valid topologic face. Returning None.") return None if not Topology.IsInstance(origin, "Vertex"): origin = Topology.Centroid(face) if not Topology.IsInstance(origin, "Vertex"): print("Edge.ByFaceNormal - Error: The input origin parameter is not a valid topologic origin. Returning None.") return None n = Face.Normal(face) v2 = Topology.Translate(origin, n[0], n[1], n[2]) edge = Edge.ByStartVertexEndVertex(origin, v2, tolerance=tolerance, silent=True) if not Topology.IsInstance(edge, "Edge"): print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.") return None edge = Edge.SetLength(edge, length, bothSides=False) if not Topology.IsInstance(edge, "Edge"): print("Edge.ByFaceNormal - Error: Could not create an edge. Returning None.") return None return edge
def ByOffset2D(edge, offset: float = 1.0, tolerance: float = 0.0001)
-
Creates and edge offset from the input edge. This method is intended for edges that are in the XY plane.
Parameters
edge
:topologic_core.Edge
- The input edge.
offset
:float
, optional- The desired offset. The default is 1.
tolerance
:float , optiona
- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- An edge offset from the input edge.
Expand source code
@staticmethod def ByOffset2D(edge, offset: float = 1.0, tolerance: float = 0.0001): """ Creates and edge offset from the input edge. This method is intended for edges that are in the XY plane. Parameters ---------- edge : topologic_core.Edge The input edge. offset : float , optional The desired offset. The default is 1. tolerance : float , optiona The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge An edge offset from the input edge. """ from topologicpy.Topology import Topology from topologicpy.Vector import Vector n = Edge.Normal(edge) n = Vector.Normalize(n) n = Vector.Multiply(n, offset, tolerance) edge = Topology.Translate(edge, n[0], n[1], n[2]) return edge
def ByStartVertexEndVertex(vertexA, vertexB, tolerance: float = 0.0001, silent=False)
-
Creates a straight edge that connects the input vertices.
Parameters
vertexA
:topologic_core.Vertex
- The first input vertex. This is considered the start vertex.
vertexB
:toopologic.Vertex
- The second input vertex. This is considered the end vertex.
tolerance
:float
, optional- The desired tolerance to decide if an Edge can be created. The default is 0.0001.
silent
:bool
, optional- If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
Returns
edge
:topologic_core.Edge
- The created edge.
Expand source code
@staticmethod def ByStartVertexEndVertex(vertexA, vertexB, tolerance: float = 0.0001, silent=False): """ Creates a straight edge that connects the input vertices. Parameters ---------- vertexA : topologic_core.Vertex The first input vertex. This is considered the start vertex. vertexB : toopologic.Vertex The second input vertex. This is considered the end vertex. tolerance : float , optional The desired tolerance to decide if an Edge can be created. The default is 0.0001. silent : bool , optional If set to False, error and warning messages are printed. Otherwise, they are not. The default is False. Returns ------- edge : topologic_core.Edge The created edge. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology edge = None if not Topology.IsInstance(vertexA, "Vertex"): if not silent: print("Edge.ByStartVertexEndVertex - Error: The input vertexA parameter is not a valid topologic vertex. Returning None.") return None if not Topology.IsInstance(vertexB, "Vertex"): if not silent: print("Edge.ByStartVertexEndVertex - Error: The input vertexB parameter is not a valid topologic vertex. Returning None.") return None if Topology.IsSame(vertexA, vertexB): if not silent: print("Edge.ByStartVertexEndVertex - Error: The input vertexA and vertexB parameters are the same vertex. Returning None.") return None if Vertex.Distance(vertexA, vertexB) < tolerance: if not silent: print("Edge.ByStartVertexEndVertex - Error: The distance between the input vertexA and vertexB parameters is less than the input tolerance. Returning None.") return None try: edge = topologic.Edge.ByStartVertexEndVertex(vertexA, vertexB) # Hook to Core except: if not silent: print("Edge.ByStartVertexEndVertex - Error: Could not create an edge. Returning None.") edge = None return edge
def ByVertices(*args, tolerance: float = 0.0001, silent: bool = False)
-
Creates a straight edge that connects the input list of vertices.
Parameters
vertices
:list
- The input list of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
tolerance
:float
, optional- The desired tolerance to decide if an edge can be created. The default is 0.0001.
silent
:bool
, optional- If set to True, error and warning messages are printed. Otherwise, they are not. The default is True.
Returns
topologic_core.Edge
- The created edge.
Expand source code
@staticmethod def ByVertices(*args, tolerance: float = 0.0001, silent: bool = False): """ Creates a straight edge that connects the input list of vertices. Parameters ---------- vertices : list The input list of vertices. The first item is considered the start vertex and the last item is considered the end vertex. tolerance : float , optional The desired tolerance to decide if an edge can be created. The default is 0.0001. silent : bool , optional If set to True, error and warning messages are printed. Otherwise, they are not. The default is True. Returns ------- topologic_core.Edge The created edge. """ from topologicpy.Helper import Helper from topologicpy.Topology import Topology if len(args) == 0: print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.") return None if len(args) == 1: vertices = args[0] if isinstance(vertices, list): if len(vertices) == 0: if not silent: print("Edge.ByVertices - Error: The input vertices parameter is an empty list. Returning None.") return None else: vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")] if len(vertexList) == 0: if not silent: print("Edge.ByVertices - Error: The input vertices parameter does not contain any valid vertices. Returning None.") return None else: if not silent: print("Edge.ByVertices - Warning: The input vertices parameter contains only one vertex. Returning None.") return None else: vertexList = Helper.Flatten(list(args)) vertexList = [x for x in vertexList if Topology.IsInstance(x, "Vertex")] if len(vertexList) < 2: if not silent: print("Edge.ByVertices - Error: The input vertices parameter has less than two vertices. Returning None.") return None return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance, silent=silent)
def ByVerticesCluster(cluster, tolerance: float = 0.0001)
-
Creates a straight edge that connects the input cluster of vertices.
Parameters
cluster
:topologic_core.Cluster
- The input cluster of vertices. The first item is considered the start vertex and the last item is considered the end vertex.
tolerance
:float
, optional- The desired tolerance to decide if an edge can be created. The default is 0.0001.
Returns
topologic_core.Edge
- The created edge.
Expand source code
@staticmethod def ByVerticesCluster(cluster, tolerance: float = 0.0001): """ Creates a straight edge that connects the input cluster of vertices. Parameters ---------- cluster : topologic_core.Cluster The input cluster of vertices. The first item is considered the start vertex and the last item is considered the end vertex. tolerance : float , optional The desired tolerance to decide if an edge can be created. The default is 0.0001. Returns ------- topologic_core.Edge The created edge. """ from topologicpy.Cluster import Cluster from topologicpy.Topology import Topology if not Topology.IsInstance(cluster, "Cluster"): print("Edge.ByVerticesCluster - Error: The input cluster parameter is not a valid topologic cluster. Returning None.") return None vertices = Cluster.Vertices(cluster) vertexList = [x for x in vertices if Topology.IsInstance(x, "Vertex")] if len(vertexList) < 2: print("Edge.ByVerticesCluster - Error: The input cluster parameter contains less than two vertices. Returning None.") return None return Edge.ByStartVertexEndVertex(vertexList[0], vertexList[-1], tolerance=tolerance)
def Direction(edge, mantissa: int = 6) ‑> list
-
Returns the direction of the input edge expressed as a list of three numbers.
Parameters
edge
:topologic_core.Edge
- The input edge.
mantissa
:int
, optional- The desired length of the mantissa. The default is 6.
Returns
list
- The direction of the input edge.
Expand source code
@staticmethod def Direction(edge, mantissa: int = 6) -> list: """ Returns the direction of the input edge expressed as a list of three numbers. Parameters ---------- edge : topologic_core.Edge The input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. Returns ------- list The direction of the input edge. """ from topologicpy.Vector import Vector from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Direction - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None ev = edge.EndVertex() sv = edge.StartVertex() x = ev.X() - sv.X() y = ev.Y() - sv.Y() z = ev.Z() - sv.Z() uvec = Vector.Normalize([x,y,z]) x = round(uvec[0], mantissa) y = round(uvec[1], mantissa) z = round(uvec[2], mantissa) return [x, y, z]
def EndVertex(edge)
-
Returns the end vertex of the input edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
Returns
topologic_core.Vertex
- The end vertex of the input edge.
Expand source code
@staticmethod def EndVertex(edge): """ Returns the end vertex of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. Returns ------- topologic_core.Vertex The end vertex of the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.EndVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vert = None try: vert = edge.EndVertex() except: vert = None return vert
def Extend(edge, distance: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001)
-
Extends the input edge by the input distance.
Parameters
edge
:topologic_core.Edge
- The input edge.
distance
:float
, optional- The offset distance. The default is 1.
bothSides
:bool
, optional- If set to True, the edge will be extended by half the distance at each end. The default is False.
reverse
:bool
, optional- If set to True, the edge will be extended from its start vertex. Otherwise, it will be extended from its end vertex. The default is False.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The extended edge.
Expand source code
@staticmethod def Extend(edge, distance: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001): """ Extends the input edge by the input distance. Parameters ---------- edge : topologic_core.Edge The input edge. distance : float , optional The offset distance. The default is 1. bothSides : bool , optional If set to True, the edge will be extended by half the distance at each end. The default is False. reverse : bool , optional If set to True, the edge will be extended from its start vertex. Otherwise, it will be extended from its end vertex. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The extended edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Extend - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None distance = abs(distance) if distance < tolerance: return edge sv = Edge.StartVertex(edge) ev = Edge.EndVertex(edge) if bothSides: sve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=sv, tolerance=tolerance) eve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=ev, tolerance=tolerance) elif reverse: sve = Edge.VertexByDistance(edge, distance=-distance, origin=sv, tolerance=tolerance) eve = Edge.EndVertex(edge) else: sve = Edge.StartVertex(edge) eve = Edge.VertexByDistance(edge, distance=distance, origin=ev, tolerance=tolerance) return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
def ExtendToEdge2D(edgeA, edgeB, tolerance: float = 0.0001)
-
Extends the first input edge to meet the second input edge. This works only in the XY plane. Z coordinates are ignored.
Parameters
edgeA
:topologic_core.Edge
- The first input edge.
edgeB
:topologic_core.Edge
- The second input edge.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The extended edge.
Expand source code
@staticmethod def ExtendToEdge2D(edgeA, edgeB, tolerance: float = 0.0001): """ Extends the first input edge to meet the second input edge. This works only in the XY plane. Z coordinates are ignored. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The extended edge. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): print("Edge.ExtendToEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.ExtendToEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None sva = Edge.StartVertex(edgeA) eva = Edge.EndVertex(edgeA) intVertex = Edge.Intersect2D(edgeA, edgeB) if intVertex and not (Vertex.IsInternal(intVertex, edgeA)): e1 = Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True) e2 = Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True) l1 = Edge.Length(e1) l2 = Edge.Length(e2) if l1 > l2: return e1 else: return e2 print("Edge.ExtendToEdge2D - Error: The operation failed. Returning None.") return None
def Index(edge, edges: list, strict: bool = False, tolerance: float = 0.0001) ‑> int
-
Returns index of the input edge in the input list of edges
Parameters
edge
:topologic_core.Edge
- The input edge.
edges
:list
- The input list of edges.
strict
:bool
, optional- If set to True, the edge must be strictly identical to the one found in the list. Otherwise, a distance comparison is used. The default is False.
tolerance
:float
, optional- The tolerance for computing if the input edge is identical to an edge from the list. The default is 0.0001.
Returns
int
- The index of the input edge in the input list of edges.
Expand source code
@staticmethod def Index(edge, edges: list, strict: bool = False, tolerance: float = 0.0001) -> int: """ Returns index of the input edge in the input list of edges Parameters ---------- edge : topologic_core.Edge The input edge. edges : list The input list of edges. strict : bool , optional If set to True, the edge must be strictly identical to the one found in the list. Otherwise, a distance comparison is used. The default is False. tolerance : float , optional The tolerance for computing if the input edge is identical to an edge from the list. The default is 0.0001. Returns ------- int The index of the input edge in the input list of edges. """ from topologicpy.Topology import Topology from topologicpy.Vertex import Vertex if not Topology.IsInstance(edge, "Edge"): print("Edge.Index - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not isinstance(edges, list): print("Edge.Index - Error: The input edges parameter is not a valid list. Returning None.") return None edges = [e for e in edges if Topology.IsInstance(e, "Edge")] if len(edges) < 1: print("Edge.Index - Error: The input edges parameter contains no valid edges. Returning None.") return None sva = Edge.StartVertex(edge) eva = Edge.EndVertex(edge) for i in range(len(edges)): if strict: if Topology.IsSame(edge, edges[i]): return i else: svb = Edge.StartVertex(edges[i]) evb = Edge.EndVertex(edges[i]) dsvsv = Vertex.Distance(sva, svb) devev = Vertex.Distance(eva, evb) if dsvsv < tolerance and devev < tolerance: return i dsvev = Vertex.Distance(sva, evb) devsv = Vertex.Distance(eva, svb) if dsvev < tolerance and devsv < tolerance: return i return None
def Intersect2D(edgeA, edgeB, silent: bool = False)
-
Returns the intersection of the two input edges as a topologic_core.Vertex. This works only in the XY plane. Z coordinates are ignored.
Parameters
edgeA
:topologic_core.Edge
- The first input edge.
edgeB
:topologic_core.Edge
- The second input edge.
silent
:bool
, optional- If set to False, error and warning messages are displayed. Otherwise they are not. The default is False.
Returns
topologic_core.Vertex
- The intersection of the two input edges.
Expand source code
@staticmethod def Intersect2D(edgeA, edgeB, silent: bool = False): """ Returns the intersection of the two input edges as a topologic_core.Vertex. This works only in the XY plane. Z coordinates are ignored. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. silent : bool , optional If set to False, error and warning messages are displayed. Otherwise they are not. The default is False. Returns ------- topologic_core.Vertex The intersection of the two input edges. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): if not silent: print("Edge.Intersect2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): if not silent: print("Edge.Intersect2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None sva = Edge.StartVertex(edgeA) eva = Edge.EndVertex(edgeA) svb = Edge.StartVertex(edgeB) evb = Edge.EndVertex(edgeB) # Line AB represented as a1x + b1y = c1 a1 = Vertex.Y(eva) - Vertex.Y(sva) b1 = Vertex.X(sva) - Vertex.X(eva) c1 = a1*(Vertex.X(sva)) + b1*(Vertex.Y(sva)) # Line CD represented as a2x + b2y = c2 a2 = Vertex.Y(evb) - Vertex.Y(svb) b2 = Vertex.X(svb) - Vertex.X(evb) c2 = a2*(Vertex.X(svb)) + b2*(Vertex.Y(svb)) determinant = a1*b2 - a2*b1 if (determinant == 0): # The lines are parallel. This is simplified # by returning a pair of FLT_MAX if not silent: print("Edge.Intersect2D - Warning: The input edgeA and edgeB parameters are parallel edges. Returning None.") return None else: x = (b2*c1 - b1*c2)/determinant y = (a1*c2 - a2*c1)/determinant return Vertex.ByCoordinates(x,y,0)
def IsCollinear(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001) ‑> bool
-
Return True if the two input edges are collinear. Returns False otherwise. This code is based on a contribution by https://github.com/gaoxipeng
Parameters
edgeA
:topologic_core.Edge
- The first input edge.
edgeB
:topologic_core.Edge
- The second input edge.
mantissa
:int
, optional- The desired length of the mantissa. The default is 6.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
bool
- True if the two edges are collinear. False otherwise.
Expand source code
@staticmethod def IsCollinear(edgeA, edgeB, mantissa: int = 6, tolerance: float = 0.0001) -> bool: """ Return True if the two input edges are collinear. Returns False otherwise. This code is based on a contribution by https://github.com/gaoxipeng Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- bool True if the two edges are collinear. False otherwise. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology import numpy as np if not Topology.IsInstance(edgeA, "Edge"): print("Edge.IsCollinear - Error: The input parameter edgeA is not a valid edge. Returning None") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.IsCollinear - Error: The input parameter edgeB is not a valid edge. Returning None") return None if Edge.Length(edgeA) < tolerance: print("Edge.IsCollinear - Error: The length of edgeA is less than the tolerance. Returning None") return None if Edge.Length(edgeB) < tolerance: print("Edge.IsCollinear - Error: The length of edgeB is less than the tolerance. Returning None") return None # Get start and end points of the first edge start_a = Edge.StartVertex(edgeA) end_a = Edge.EndVertex(edgeA) start_a_coords = np.array([Vertex.X(start_a), Vertex.Y(start_a), Vertex.Z(start_a)]) end_a_coords = np.array( [Vertex.X(end_a, mantissa=mantissa), Vertex.Y(end_a, mantissa=mantissa), Vertex.Z(end_a, mantissa=mantissa)]) # Calculate the direction vector of the first edge direction_a = end_a_coords - start_a_coords # Normalize the direction vector norm_a = np.linalg.norm(direction_a) if norm_a == 0: print("Edge.IsCollinear - Error: Division by zero. Returning None.") return None direction_a /= norm_a # Function to calculate perpendicular distance from a point to the line defined by a point and direction vector def distance_from_line(point, line_point, line_dir): point = np.array([Vertex.X(point, mantissa=mantissa), Vertex.Y(point, mantissa=mantissa), Vertex.Z(point, mantissa=mantissa)]) line_point = np.array(line_point) diff = point - line_point cross_product = np.cross(diff, line_dir) line_dir_norm = np.linalg.norm(line_dir) if line_dir_norm == 0: print("Edge.IsCollinear - Error: Division by zero. Returning None.") return None distance = np.linalg.norm(cross_product) / np.linalg.norm(line_dir) return distance # Get start and end points of the second edge start_b = Edge.StartVertex(edgeB) end_b = Edge.EndVertex(edgeB) # Calculate distances for start and end vertices of the second edge to the line defined by the first edge distance_start = distance_from_line(start_b, start_a_coords, direction_a) distance_end = distance_from_line(end_b, start_a_coords, direction_a) # Check if both distances are within tolerance return bool(distance_start < tolerance) and bool(distance_end < tolerance)
def IsParallel(edgeA, edgeB, mantissa: int = 6, angTolerance: float = 0.1) ‑> bool
-
Return True if the two input edges are parallel. Returns False otherwise.
Parameters
edgeA
:topologic_core.Edge
- The first input edge.
edgeB
:topologic_core.Edge
- The second input edge.
mantissa
:int
, optional- The desired length of the mantissa. The default is 6.
angTolerance
:float
, optional- The angular tolerance used for the test. The default is 0.1.
Returns
bool
- True if the two edges are collinear. False otherwise.
Expand source code
@staticmethod def IsParallel(edgeA, edgeB, mantissa: int = 6, angTolerance: float = 0.1) -> bool: """ Return True if the two input edges are parallel. Returns False otherwise. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. angTolerance : float , optional The angular tolerance used for the test. The default is 0.1. Returns ------- bool True if the two edges are collinear. False otherwise. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): print("Edge.IsParallel - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.IsParallel - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None ang = Edge.Angle(edgeA, edgeB, mantissa=mantissa, bracket=True) if abs(ang) < angTolerance or abs(180 - ang) < angTolerance: return True return False
def Length(edge, mantissa: int = 6) ‑> float
-
Returns the length of the input edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
mantissa
:int
, optional- The desired length of the mantissa. The default is 6.
Returns
float
- The length of the input edge.
Expand source code
@staticmethod def Length(edge, mantissa: int = 6) -> float: """ Returns the length of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. mantissa : int , optional The desired length of the mantissa. The default is 6. Returns ------- float The length of the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Length - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None length = None try: length = round(topologic.EdgeUtility.Length(edge), mantissa) # Hook to Core except: length = None if length == None: print("Edge.Length - Error: Could not compute the length of the input edge parameter. Returning None.") return length
def Line(origin=None, length: float = 1, direction: list = [1, 0, 0], placement: str = 'center', tolerance: float = 0.0001)
-
Creates a straight edge (line) using the input parameters.
Parameters
origin
:topologic_core.Vertex
, optional- The origin location of the box. The default is None which results in the edge being placed at (0, 0, 0).
length
:float
, optional- The desired length of the edge. The default is 1.0.
direction
:list
, optional- The desired direction (vector) of the edge. The default is [1,0,0] (along the X-axis).
placement
:str
, optional- The desired placement of the edge. The options are: 1. "center" which places the center of the edge at the origin. 2. "start" which places the start of the edge at the origin. 3. "end" which places the end of the edge at the origin. The default is "center".
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The created edge
Expand source code
@staticmethod def Line(origin= None, length: float = 1, direction: list = [1,0,0], placement: str ="center", tolerance: float = 0.0001): """ Creates a straight edge (line) using the input parameters. Parameters ---------- origin : topologic_core.Vertex , optional The origin location of the box. The default is None which results in the edge being placed at (0, 0, 0). length : float , optional The desired length of the edge. The default is 1.0. direction : list , optional The desired direction (vector) of the edge. The default is [1,0,0] (along the X-axis). placement : str , optional The desired placement of the edge. The options are: 1. "center" which places the center of the edge at the origin. 2. "start" which places the start of the edge at the origin. 3. "end" which places the end of the edge at the origin. The default is "center". tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The created edge """ from topologicpy.Vertex import Vertex from topologicpy.Vector import Vector from topologicpy.Topology import Topology if origin == None: origin = Vertex.Origin() if not Topology.IsInstance(origin, "Vertex"): print("Edge.Line - Error: The input origin parameter is not a valid topologic vertex. Returning None.") return None if length <= 0: print("Edge.Line - Error: The input length is less than or equal to zero. Returning None.") return None if not isinstance(direction, list): print("Edge.Line - Error: The input direction parameter is not a valid list. Returning None.") return None if not len(direction) == 3: print("Edge.Line - Error: The length of the input direction parameter is not equal to three. Returning None.") return None direction = Vector.Normalize(direction) if "center" in placement.lower(): sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length*0.5) ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length) return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True) if "start" in placement.lower(): sv = origin ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length) return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True) if "end" in placement.lower(): sv = Topology.TranslateByDirectionDistance(origin, direction=Vector.Reverse(direction), distance=length) ev = Topology.TranslateByDirectionDistance(sv, direction=direction, distance=length) return Edge.ByVertices([sv,ev], tolerance=tolerance, silent=True) else: print("Edge.Line - Error: The input placement string is not one of center, start, or end. Returning None.") return None
def Normal(edge, angle: float = 0.0)
-
Returns the normal (perpendicular) vector to the input edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
angle
:float
, optional- The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge by the angle value around the axis defined by the input edge. The default is 0.0.
Returns
list
- The normal (perpendicular ) vector to the input edge.
Expand source code
@staticmethod def Normal(edge, angle: float = 0.0): """ Returns the normal (perpendicular) vector to the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. angle : float , optional The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge by the angle value around the axis defined by the input edge. The default is 0.0. Returns ------- list The normal (perpendicular ) vector to the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Normal - Error: The input edge parameter is not a valid edge. Returning None.") return None normal_edge = Edge.NormalAsEdge(edge, length=1.0, u=0.5, angle=angle) return Edge.Direction(normal_edge)
def NormalAsEdge(edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0)
-
Returns the normal (perpendicular) vector to the input edge as an edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
length
:float
, optional- The desired length of the normal edge. The default is 1.0.
u
:float
, optional- The desired u parameter placement of the normal edge. A value of 0.0 places the normal edge at the start vertex of the input edge, a value of 0.5 places the normal edge at the midpoint of the input edge, and a value of 1.0 places the normal edge at the end vertex of the input edge. The default is 0.5
angle
:float
, optional- The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge by the angle value around the axis defined by the input edge. The default is 0.0.
Returns
topologic_core.Edge
- The normal (perpendicular) vector to the input edge as an edge.
Expand source code
@staticmethod def NormalAsEdge(edge, length: float = 1.0, u: float = 0.5, angle: float = 0.0): """ Returns the normal (perpendicular) vector to the input edge as an edge. Parameters ---------- edge : topologic_core.Edge The input edge. length : float , optional The desired length of the normal edge. The default is 1.0. u : float , optional The desired u parameter placement of the normal edge. A value of 0.0 places the normal edge at the start vertex of the input edge, a value of 0.5 places the normal edge at the midpoint of the input edge, and a value of 1.0 places the normal edge at the end vertex of the input edge. The default is 0.5 angle : float , optional The desired rotational offset angle in degrees for the normal edge. This rotates the normal edge by the angle value around the axis defined by the input edge. The default is 0.0. Returns ------- topologic_core.Edge The normal (perpendicular) vector to the input edge as an edge. """ import numpy as np from numpy.linalg import norm import topologic_core as topologic from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology def calculate_normal(start_vertex, end_vertex): start_vertex = [float(x) for x in start_vertex] end_vertex = [float(x) for x in end_vertex] # Calculate the direction vector of the line segment direction_vector = np.array(end_vertex) - np.array(start_vertex) # Calculate the normal vector by swapping components and negating one of them normal_vector = np.array([-direction_vector[1], direction_vector[0], 0]) # Normalize the normal vector normal_vector /= norm(normal_vector) return normal_vector def calculate_normal_line(start_vertex, end_vertex): # Calculate the normal vector of the line normal_vector = calculate_normal(start_vertex, end_vertex) # Calculate the new end vertex for the normal line to have a length of 1 normal_end_vertex = np.array(start_vertex) + normal_vector # Return the start and end vertices of the normal line return start_vertex, list(normal_end_vertex) if not Topology.IsInstance(edge, "Edge"): print("Edge.NormalAsEdge - Error: The input edge parameter is not a valid edge. Returning None.") return None if length <= 0.0: print("Edge.NormalAsEdge - Error: The input length parameter is not a positive number greater than zero. Returning None.") return None edge_direction = Edge.Direction(edge) x, y, z = edge_direction start_vertex = Vertex.Coordinates(Edge.StartVertex(edge)) end_vertex = Vertex.Coordinates(Edge.EndVertex(edge)) normal_line_start, normal_line_end = calculate_normal_line(start_vertex, end_vertex) sv = Vertex.ByCoordinates(normal_line_start) ev = Vertex.ByCoordinates(list(normal_line_end)) normal_edge = Edge.ByVertices([sv, ev]) normal_edge = Edge.SetLength(normal_edge, length, bothSides=False) normal_edge = Topology.Rotate(normal_edge, origin=Edge.StartVertex(normal_edge), axis=[x,y,z], angle=angle) dist = Edge.Length(edge)*u normal_edge = Topology.TranslateByDirectionDistance(normal_edge, edge_direction, dist) return normal_edge
def Normalize(edge, useEndVertex: bool = False, tolerance: float = 0.0001)
-
Creates a normalized edge that has the same direction as the input edge, but a length of 1.
Parameters
edge
:topologic_core.Edge
- The input edge.
useEndVertex
:bool
, optional- If True the normalized edge end vertex will be placed at the end vertex of the input edge. Otherwise, the normalized edge start vertex will be placed at the start vertex of the input edge. The default is False.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The normalized edge.
Expand source code
@staticmethod def Normalize(edge, useEndVertex: bool = False, tolerance: float = 0.0001): """ Creates a normalized edge that has the same direction as the input edge, but a length of 1. Parameters ---------- edge : topologic_core.Edge The input edge. useEndVertex : bool , optional If True the normalized edge end vertex will be placed at the end vertex of the input edge. Otherwise, the normalized edge start vertex will be placed at the start vertex of the input edge. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The normalized edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Normalize - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not useEndVertex: sv = edge.StartVertex() ev = Edge.VertexByDistance(edge, 1.0, edge.StartVertex()) else: sv = Edge.VertexByDistance(edge, 1.0, edge.StartVertex()) ev = edge.EndVertex() return Edge.ByVertices([sv, ev], tolerance=tolerance)
def ParameterAtVertex(edge, vertex, mantissa: int = 6, silent: bool = False) ‑> float
-
Returns the u parameter along the input edge based on the location of the input vertex.
Parameters
edge
:topologic_core.Edge
- The input edge.
vertex
:topologic_core.Vertex
- The input vertex.
mantissa
:int
, optional- The desired length of the mantissa. The default is 6.
silent
:bool
, optional- If set to False, error and warning messages are printed. Otherwise, they are not. The default is False.
Returns
float
- The u parameter along the input edge based on the location of the input vertex.
Expand source code
@staticmethod def ParameterAtVertex(edge, vertex, mantissa: int = 6, silent: bool = False) -> float: """ Returns the *u* parameter along the input edge based on the location of the input vertex. Parameters ---------- edge : topologic_core.Edge The input edge. vertex : topologic_core.Vertex The input vertex. mantissa : int , optional The desired length of the mantissa. The default is 6. silent : bool , optional If set to False, error and warning messages are printed. Otherwise, they are not. The default is False. Returns ------- float The *u* parameter along the input edge based on the location of the input vertex. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): if not silent: print("Edge.ParameterAtVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(vertex, "Vertex"): if not silent: print("Edge.ParameterAtVertex - Error: The input vertex parameter is not a valid topologic vertex. Returning None.") return None parameter = None try: parameter = topologic.EdgeUtility.ParameterAtPoint(edge, vertex) # Hook to Core except: return None #Return silently because topologic C++ returns a runtime error if point is not on curve. return round(parameter, mantissa)
def Reverse(edge, tolerance: float = 0.0001)
-
Creates an edge that has the reverse direction of the input edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The reversed edge.
Expand source code
@staticmethod def Reverse(edge, tolerance: float = 0.0001): """ Creates an edge that has the reverse direction of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The reversed edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Reverse - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None return Edge.ByVertices([edge.EndVertex(), edge.StartVertex()], tolerance=tolerance)
def SetLength(edge, length: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001)
-
Returns an edge with the new length in the same direction as the input edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
length
:float
, optional- The desired length of the edge. The default is 1.
bothSides
:bool
, optional- If set to True, the edge will be offset symmetrically from each end. The default is True.
reverse
:bool
, optional- If set to True, the edge will be offset from its start vertex. Otherwise, it will be offset from its end vertex. The default is False.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The extended edge.
Expand source code
@staticmethod def SetLength(edge , length: float = 1.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001): """ Returns an edge with the new length in the same direction as the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. length : float , optional The desired length of the edge. The default is 1. bothSides : bool , optional If set to True, the edge will be offset symmetrically from each end. The default is True. reverse : bool , optional If set to True, the edge will be offset from its start vertex. Otherwise, it will be offset from its end vertex. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The extended edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.SetLength - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None distance = (length - Edge.Length(edge)) if distance > 0: return Edge.Extend(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance) return Edge.Trim(edge=edge, distance=distance, bothSides=bothSides, reverse=reverse, tolerance=tolerance)
def StartVertex(edge)
-
Returns the start vertex of the input edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
Returns
topologic_core.Vertex
- The start vertex of the input edge.
Expand source code
@staticmethod def StartVertex(edge): """ Returns the start vertex of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. Returns ------- topologic_core.Vertex The start vertex of the input edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.StartVertex - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vert = None try: vert = edge.StartVertex() except: vert = None return vert
def Trim(edge, distance: float = 0.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001)
-
Trims the input edge by the input distance.
Parameters
edge
:topologic_core.Edge
- The input edge.
distance
:float
, optional- The offset distance. The default is 0.
bothSides
:bool
, optional- If set to True, the edge will be trimmed by half the distance at each end. The default is False.
reverse
:bool
, optional- If set to True, the edge will be trimmed from its start vertex. Otherwise, it will be trimmed from its end vertex. The default is False.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The trimmed edge.
Expand source code
@staticmethod def Trim(edge, distance: float = 0.0, bothSides: bool = True, reverse: bool = False, tolerance: float = 0.0001): """ Trims the input edge by the input distance. Parameters ---------- edge : topologic_core.Edge The input edge. distance : float , optional The offset distance. The default is 0. bothSides : bool , optional If set to True, the edge will be trimmed by half the distance at each end. The default is False. reverse : bool , optional If set to True, the edge will be trimmed from its start vertex. Otherwise, it will be trimmed from its end vertex. The default is False. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The trimmed edge. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Trim - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None distance = abs(distance) if distance == 0: return edge if distance < tolerance: print("Edge.Trim - Warning: The input distance parameter is less than the input tolerance parameter. Returning the input edge.") return edge sv = Edge.StartVertex(edge) ev = Edge.EndVertex(edge) if bothSides: sve = Edge.VertexByDistance(edge, distance=distance*0.5, origin=sv, tolerance=tolerance) eve = Edge.VertexByDistance(edge, distance=-distance*0.5, origin=ev, tolerance=tolerance) elif reverse: sve = Edge.VertexByDistance(edge, distance=distance, origin=sv, tolerance=tolerance) eve = Edge.EndVertex(edge) else: sve = Edge.StartVertex(edge) eve = Edge.VertexByDistance(edge, distance=-distance, origin=ev, tolerance=tolerance) return Edge.ByVertices([sve, eve], tolerance=tolerance, silent=True)
def TrimByEdge2D(edgeA, edgeB, reverse: bool = False, tolerance: float = 0.0001)
-
Trims the first input edge by the second input edge. This works only in the XY plane. Z coordinates are ignored.
Parameters
edgeA
:topologic_core.Edge
- The first input edge.
edgeB
:topologic_core.Edge
- The second input edge.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Edge
- The trimmed edge.
Expand source code
@staticmethod def TrimByEdge2D(edgeA, edgeB, reverse: bool = False, tolerance: float = 0.0001): """ Trims the first input edge by the second input edge. This works only in the XY plane. Z coordinates are ignored. Parameters ---------- edgeA : topologic_core.Edge The first input edge. edgeB : topologic_core.Edge The second input edge. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Edge The trimmed edge. """ from topologicpy.Vertex import Vertex from topologicpy.Topology import Topology if not Topology.IsInstance(edgeA, "Edge"): print("Edge.TrimByEdge2D - Error: The input edgeA parameter is not a valid topologic edge. Returning None.") return None if not Topology.IsInstance(edgeB, "Edge"): print("Edge.TrimByEdge2D - Error: The input edgeB parameter is not a valid topologic edge. Returning None.") return None sva = Edge.StartVertex(edgeA) eva = Edge.EndVertex(edgeA) intVertex = Edge.Intersect2D(edgeA, edgeB) if intVertex and (Vertex.IsInternal(intVertex, edgeA)): if reverse: return Edge.ByVertices([eva, intVertex], tolerance=tolerance, silent=True) else: return Edge.ByVertices([sva, intVertex], tolerance=tolerance, silent=True) return edgeA
def VertexByDistance(edge, distance: float = 0.0, origin=None, tolerance: float = 0.0001)
-
Creates a vertex along the input edge offset by the input distance from the input origin.
Parameters
edge
:topologic_core.Edge
- The input edge.
distance
:float
, optional- The offset distance. The default is 0.
origin
:topologic_core.Vertex
, optional- The origin of the offset distance. If set to None, the origin will be set to the start vertex of the input edge. The default is None.
tolerance
:float
, optional- The desired tolerance. The default is 0.0001.
Returns
topologic_core.Vertex
- The created vertex.
Expand source code
@staticmethod def VertexByDistance(edge, distance: float = 0.0, origin= None, tolerance: float = 0.0001): """ Creates a vertex along the input edge offset by the input distance from the input origin. Parameters ---------- edge : topologic_core.Edge The input edge. distance : float , optional The offset distance. The default is 0. origin : topologic_core.Vertex , optional The origin of the offset distance. If set to None, the origin will be set to the start vertex of the input edge. The default is None. tolerance : float , optional The desired tolerance. The default is 0.0001. Returns ------- topologic_core.Vertex The created vertex. """ from topologicpy.Vertex import Vertex from topologicpy.Vector import Vector from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.TrimByEdge2D - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None if not origin: origin = edge.StartVertex() if not Topology.IsInstance(origin, "Vertex"): print("Edge.TrimByEdge2D - Error: The input origin parameter is not a valid topologic vertex. Returning None.") return None sv = edge.StartVertex() ev = edge.EndVertex() vx = ev.X() - sv.X() vy = ev.Y() - sv.Y() vz = ev.Z() - sv.Z() vector = Vector.Normalize([vx, vy, vz]) vector = Vector.Multiply(vector, distance, tolerance) return Vertex.ByCoordinates(origin.X()+vector[0], origin.Y()+vector[1], origin.Z()+vector[2])
def VertexByParameter(edge, u: float = 0.0)
-
Creates a vertex along the input edge offset by the input u parameter.
Parameters
edge
:topologic_core.Edge
- The input edge.
u
:float
, optional- The u parameter along the input topologic Edge. A parameter of 0 returns the start vertex. A parameter of 1 returns the end vertex. The default is 0.
Returns
topologic_core.Vertex
- The created vertex.
Expand source code
@staticmethod def VertexByParameter(edge, u: float = 0.0): """ Creates a vertex along the input edge offset by the input *u* parameter. Parameters ---------- edge : topologic_core.Edge The input edge. u : float , optional The *u* parameter along the input topologic Edge. A parameter of 0 returns the start vertex. A parameter of 1 returns the end vertex. The default is 0. Returns ------- topologic_core.Vertex The created vertex. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.VertexByParameter - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vertex = None if u == 0: vertex = edge.StartVertex() elif u == 1: vertex = edge.EndVertex() else: dir = Edge.Direction(edge) edge_length = Edge.Length(edge) dist = edge_length*u vertex = Topology.TranslateByDirectionDistance(Edge.StartVertex(edge), direction=dir, distance=dist) return vertex
def Vertices(edge) ‑> list
-
Returns the list of vertices of the input edge.
Parameters
edge
:topologic_core.Edge
- The input edge.
Returns
list
- The list of vertices.
Expand source code
@staticmethod def Vertices(edge) -> list: """ Returns the list of vertices of the input edge. Parameters ---------- edge : topologic_core.Edge The input edge. Returns ------- list The list of vertices. """ from topologicpy.Topology import Topology if not Topology.IsInstance(edge, "Edge"): print("Edge.Vertices - Error: The input edge parameter is not a valid topologic edge. Returning None.") return None vertices = [] _ = edge.Vertices(None, vertices) # Hook to Core return vertices