Rz = Rotation.from_axis_and_angle([0, 0, 1], math.radians(90)) Ry = Rotation.from_axis_and_angle([0, 1, 0], math.radians(90)) R = Ry * Rz block.transform(R) blank.transform(R) p0 = blank.points[0] p1 = blank.points[4] v = p1 - p0 a = p0 + v * 0.5 b = Point(0.5 * TABLE, 0, 0) T = Translation.from_vector(b - a) block.transform(T) blank.transform(T) # ============================================================================== # Export # ============================================================================== block.to_json(FILE_O) # ============================================================================== # Visualization # ==============================================================================
def face_subdiv_frame(self, fkey, rel_pos=None, move_z=None, **kwattr): """Subdivide a face by offsetting its edges inwards Creates ``verts+1`` new faces. Parameters ---------- fkey : :obj:`int` rel_pos: :obj:`list` of :obj:`float` rel_pos: :obj:`float` Returns ------- :obj:`list` of :obj:`int` Keys of newly created vertices. :obj:`list` of :obj:`int` Keys of newly created faces. :obj:`tuple` of :obj:`int` and :obj:`tuple` of :obj:`int` Face keys of removed faces and their vertex keys. """ if rel_pos == 1 or rel_pos == [1, 1, 1]: return self.face_subdiv_pyramid(fkey, move_z=move_z, **kwattr) face_center_pt = Point(*self.face_center(fkey)) face_normal = Vector(*self.face_normal(fkey)) face_coordinates = self.face_coordinates(fkey) face_halfedges = self.face_halfedges(fkey) deleted_faces = [(fkey, self.face_vertices(fkey))] self.delete_face(fkey) if move_z is None: move_z = cycle(to_list(0)) if not isinstance(move_z, cycle): move_z = cycle(to_list(move_z)) if rel_pos is None: rel_pos = cycle(to_list(0.5)) if not isinstance(rel_pos, cycle): rel_pos = cycle(to_list(rel_pos)) new_vkeys = [] for x, y, z in face_coordinates: pt = Point(x, y, z) factor = next(rel_pos) v = face_center_pt - pt pt += v * factor if move_z: z_factor = next(move_z) pt += face_normal * z_factor new_vkeys.append(self.add_vertex(x=pt.x, y=pt.y, z=pt.z)) new_fkeys = [] for i, uv in enumerate(face_halfedges): u, v = uv vkeys = [] vkeys.append(u) vkeys.append(v) vkeys.append(new_vkeys[(i + 1) % len(new_vkeys)]) vkeys.append(new_vkeys[i]) new_fkeys.append(self.add_face(vkeys)) # add new center face new_fkeys.append(self.add_face(new_vkeys)) return new_vkeys, new_fkeys, deleted_faces
def gluepoints(): def board_intersection(pt1, vec1, len1, pt2, vec2, len2): line1 = line_creator(pt1, vec1, len1) line2 = line_creator(pt2, vec2, len2) # to check whether the boards are parallel if vec1 != vec2: int_pt = intersection_line_line_xy(line1, line2) else: # expand here later to deal with gluing parallel boards return 0 # since intersection also hits when the lines intersect in their continuation, we have to add that one if distance_point_point(pt1, int_pt) < len1 / 2 and \ distance_point_point(pt2, int_pt) < len2 / 2: return int_pt else: return 0 def line_creator(pt_a, vec, length): pt_b = pt_a + scale_vector(vec, length / 2) pt_a = pt_a - scale_vector(vec, length / 2) return pt_a, pt_b def surface_calc(upper_board, lower_board, intersection): if upper_board.length_vector != lower_board.length_vector: len_intersection = lower_board.width wid_intersection = upper_board.width else: # for now we assume that they are parallel in this case, potential error source for later, though len_intersection = min(upper_board.length, lower_board.length) wid_intersection = min(upper_board.width, lower_board.width) dim1 = scale_vector(upper_board.length_vector, len_intersection * .5) dim2 = scale_vector(upper_board.width_vector, wid_intersection * .5) # this procedure is necessary only because of the glue path planning to make sure points are always ordered clockwise ang = angle_vectors_signed(dim1, dim2, Vector(0, 0, 1)) if ang > 0: pt1 = intersection + dim1 - dim2 pt2 = intersection + dim1 + dim2 pt3 = intersection - dim1 + dim2 pt4 = intersection - dim1 - dim2 else: pt1 = intersection - dim1 + dim2 pt2 = intersection + dim1 + dim2 pt3 = intersection + dim1 - dim2 pt4 = intersection - dim1 - dim2 intersection_surf = Polygon([pt1, pt2, pt3, pt4]) return intersection_surf def gluepath_creator(int_surf, path_width): def interval_checker(dimension): underflow = dimension % path_width if underflow > 0.2: no_paths = dimension // path_width + 1 new_path_width = dimension / no_paths return new_path_width else: return path_width wid_gap = int_surf[1] - int_surf[0] wid_vec = Vector(wid_gap[0], wid_gap[1], wid_gap[2]) wid = wid_vec.length wid_vec.unitize() len_gap = int_surf[2] - int_surf[1] len_vec = Vector(len_gap[0], len_gap[1], len_gap[2]) len = len_vec.length len_vec.unitize() wid_path = interval_checker(wid) len_path = interval_checker(len) path_dims = [wid_path, len_path] path_points = [] iteration = 0 path_unfinished = True current_pt = int_surf[0] + scale_vector( wid_vec, wid_path / 2) + scale_vector(len_vec, len_path / 2) current_vec = len_vec.unitized() len_left = len - len_path wid_left = wid - wid_path dims_left = [len_left, wid_left] path_points.append(current_pt) R = Rotation.from_axis_and_angle([0, 0, 1], -math.pi / 2) while path_unfinished: current_index = iteration % 2 current_dim = dims_left[current_index] if iteration > 2: current_dim -= path_dims[current_index] dims_left[current_index] = current_dim if current_dim < path_width * 0.95: break current_pt = current_pt + scale_vector(current_vec, current_dim) path_points.append(current_pt) current_vec.transform(R) current_vec.unitize() iteration += 1 if not is_point_in_polygon_xy(current_pt, int_surf): print("Error: Point not in polygon") return path_points # actual procedure for layer_number in range(1, self.layer_no): for brd in self.elements(): board = brd[1] if board.layer < layer_number: continue elif board.layer > layer_number: break else: for i, other_brd in enumerate(self.elements()): other_board = other_brd[1] if other_board.layer < layer_number - 1: continue elif other_board.layer > layer_number - 1: break else: mygluept = board_intersection( board.centre_point, board.length_vector, board.length, other_board.centre_point, other_board.length_vector, other_board.length) # if there simply is no intersection if mygluept == 0: continue gluept = Point(mygluept[0], mygluept[1], mygluept[2]) board.glue_givers.append(gluept) my_glue_surface = surface_calc( board, other_board, gluept) board.glue_surfaces.append(my_glue_surface) # ADD PARAMETER LATER TO DETERMINE THE WIDTH OF THE GLUE PATH board.glue_paths.append( gluepath_creator(my_glue_surface, self.gluepathwidth)) self.network.edge[ board.global_count][i] = self.network.node[ other_board.global_count]
secondary_board_height = 4.0 secondary_board_dimensions = [ secondary_board_width, secondary_board_height, secondary_length ] primary_interval = 12.0 primary_falloff = 100.0 primary_dedensification = 1 secondary_interval = 24.0 secondary_interval_development = 1.0 skip_centrals = True primary_direction = 0 secondary_direction = 1 origin_point = Point(0, 0, 0) origin_vector_primary = Vector(0, 1, 0) origin_vector_secondary = Vector(1, 0, 0) origin_frame = Frame(origin_point, origin_vector_primary, origin_vector_secondary) Slabassembly = Assembly() Slabassembly.layer_no = layer_no Slabassembly.gap_min = gap_min Slabassembly.primary_length = primary_length Slabassembly.secondary_length = secondary_length Slabassembly.omnidirectional = omnidirectional Slabassembly.primary_board_width_outside = primary_board_width_outside Slabassembly.primary_board_height_outside = primary_board_height_outside Slabassembly.primary_board_width_inside = primary_board_width_inside Slabassembly.primary_board_height_inside = primary_board_height_inside
def location(self): """:class:`compas.geometry.Point` - The location of the object in the scene.""" return Point(self.geometry.location)
db = self.b.get_distance_numpy(x, y, z) h = np.minimum(np.maximum(0.5 + 0.5 * (db - da) / self.r, 0), 1) return (db * (1 - h) + h * da) - self.r * h * (1 - h) # ============================================================================== # Main # ============================================================================== if __name__ == "__main__": from compas_vol.primitives import VolSphere, VolBox from compas.geometry import Box, Frame, Point, Sphere import numpy as np import matplotlib.pyplot as plt s = Sphere(Point(4, 5, 0), 7) b = Box(Frame.worldXY(), 20, 15, 10) vs = VolSphere(s) vb = VolBox(b, 2.5) u = SmoothUnion(vs, vb, 6.5) # for y in range(-15, 15): # s = '' # for x in range(-30, 30): # d = u.get_distance(Point(x*0.5, y, 0)) # if d < 0: # s += 'x' # else: # s += '.' # print(s) x, y, z = np.ogrid[-15:15:100j, -15:15:100j, -15:15:100j]
"""Example: 'frame in frame' """ from compas.geometry import Point from compas.geometry import Vector from compas.geometry import Frame point = Point(146.00, 150.00, 161.50) xaxis = Vector(0.9767, 0.0010, -0.214) yaxis = Vector(0.1002, 0.8818, 0.4609) F0 = Frame(point, xaxis, yaxis) # coordinate system F0 point = Point(35., 35., 35.) xaxis = Vector(0.604, 0.430, 0.671) yaxis = Vector(-0.631, 0.772, 0.074) f_lcf = Frame(point, xaxis, yaxis) # frame f_lcf in F0 (local coordinates) # frame in global (world) coordinate system f_wcf = F0.to_world_coords(f_lcf) print(f_wcf) f_lcf2 = F0.to_local_coords(f_wcf) # world coords back to local coords print(f_lcf2) # should equal f_lcf print(f_lcf == f_lcf2)
def __pow__(self, n): return Point(self.x ** n, self.y ** n, self.z ** n)
return 'VolSphere({})'.format(str(self.sphere)) def get_distance(self, point): if not isinstance(point, Point): point = Point(*point) d = point.distance_to_point(self.sphere.center) return d - self.sphere.radius def get_distance_numpy(self, x, y, z): import numpy as np d = np.sqrt((x - self.sphere.center.x)**2 + (y - self.sphere.center.y)**2 + (z - self.sphere.center.z)**2) - self.sphere.radius return d if __name__ == "__main__": o = VolSphere(Sphere(Point(4, 2, 0), 8.5)) print(str(o)) for y in range(-15, 15): s = '' for x in range(-30, 30): d = o.get_distance(Point(x * 0.5, 0, -y)) if d < 0: s += 'x' else: s += '.' # print(s)
def __add__(self, other): return Point(self.x + other[0], self.y + other[1], self.z + other[2])
def __mul__(self, n): return Point(n * self.x, n * self.y, n * self.z)
# ============================================================================== # Main # ============================================================================== if __name__ == '__main__': from compas.geometry import Point from compas.geometry import Vector from compas.geometry import Plane from compas.geometry import Line from compas.geometry import Polygon from compas.geometry import projection_matrix point = Point(0.0, 0.0, 0.0) normal = Vector(0.0, 0.0, 1.0) plane = Plane.from_point_and_normal(point, normal) line = Line([0.0, 0.0, 0.0], [1.0, 0.0, 0.0]) triangle = Polygon([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0]]) polygon = Polygon([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]]) p = Point(1.0, 1.0, 1.0) print(repr(p)) print(p.distance_to_point(point)) print(p.distance_to_line(line)) print(p.distance_to_plane(plane)) print(p.in_triangle(triangle))
import math from compas.geometry import Point from compas.geometry import Vector from compas.geometry import Rotation from compas.datastructures import Network from compas_plotters import NetworkPlotter lsys = "A-A++A-A-A-A++A-A++A-A++A-A-A-A++A-A-A-A++A-A-A-A++A-A++A-A++A-A-A-A++A-A++A-A++A-A-A-A++A-A++A-A++A-A-A-A++A-A-A-A++A-A-A-A++A-A++A-A++A-A-A-A++A" network = Network() step = 1. pt = Point(0, 0, 0) v = Vector(1, 0, 0) def draw(network, point, vector, s, step, last_node=None): for i, c in enumerate(s): if c == 'A': point = point + vector * step a = network.add_node(x=point.x, y=point.y, z=point.z) if last_node: network.add_edge(last_node, a) last_node = a elif c == '-': R = Rotation.from_axis_and_angle((0, 0, 1), math.radians(60)) vector.transform(R) elif c == '+': R = Rotation.from_axis_and_angle((0, 0, 1), math.radians(-60)) vector.transform(R)
import compas from math import radians from compas.datastructures import Mesh from compas.geometry import Point, Rotation, Scale, Translation from compas.geometry import trimesh_remesh before = Mesh.from_ply(compas.get_bunny()) before.cull_vertices() T = Translation.from_vector(Point(0, 0, 0) - Point(* before.centroid())) S = Scale.from_factors([100, 100, 100]) R = Rotation.from_axis_and_angle([1, 0, 0], radians(90)) before.transform(R * S * T) L = sum(before.edge_length(*edge) for edge in before.edges()) / before.number_of_edges() V, F = trimesh_remesh(before.to_vertices_and_faces(), 3 * L) after = Mesh.from_vertices_and_faces(V, F)
from compas.datastructures import Mesh from compas.geometry import Point, Box from compas.geometry import Translation, Scale from compas_view2 import app box = Box.from_diagonal([(0.0, 0.0, 0.0), (1.0, 1.0, 1.0)]) mesh = Mesh.from_shape(box) trimesh = Mesh.from_polyhedron(4) tribox = Box.from_bounding_box(trimesh.bounding_box()) S = tribox.width / box.width trimesh.transform(Scale.from_factors([S, S, S])) trimesh.transform( Translation.from_vector(Point(0.5, 0.5, 0.5) - Point(0, 0, 0))) tri = mesh.subdivide(k=3, scheme='tri') quad = mesh.subdivide(k=3, scheme='quad') corner = mesh.subdivide(k=3, scheme='corner') ck = mesh.subdivide(k=3, scheme='catmullclark') doosabin = mesh.subdivide(k=3, scheme='doosabin') frames = mesh.subdivide(offset=0.2, scheme='frames') loop = trimesh.subdivide(k=3, scheme='loop') corner.transform(Translation.from_vector([1.2 * 1, 0.0, 0.0])) loop.transform(Translation.from_vector([1.2 * 2, 0.0, 0.0])) quad.transform(Translation.from_vector([1.2 * 3, 0.0, 0.0])) ck.transform(Translation.from_vector([1.2 * 4, 0.0, 0.0])) doosabin.transform(Translation.from_vector([1.2 * 5, 0.0, 0.0])) frames.transform(Translation.from_vector([1.2 * 6, 0.0, 0.0]))
def get_distance(self, point): if not isinstance(point, Point): point = Point(*point) d = point.distance_to_point(self.sphere.center) return d - self.sphere.radius
from compas.geometry import Point from compas.geometry import Line from compas.geometry import NurbsCurve from compas.artists import Artist from compas.colors import Color line = Line(Point(0, 0, 0), Point(3, 3, 0)) curve = NurbsCurve.from_line(line) # ============================================================================== # Visualisation # ============================================================================== Artist.clear() Artist(curve).draw(color=Color.green()) for point in curve.points: Artist(point).draw() Artist.redraw()
from compas.geometry import Point, Polyline from compas.utilities import meshgrid, flatten from compas_view2.app import App from compas_occ.geometry.curves import BSplineCurve from compas_occ.geometry.surfaces import BSplineSurface points1 = [] points1.append(Point(-4, 0, 2)) points1.append(Point(-7, 2, 2)) points1.append(Point(-6, 3, 1)) points1.append(Point(-4, 3, -1)) points1.append(Point(-3, 5, -2)) spline1 = BSplineCurve.from_points(points1) points2 = [] points2.append(Point(-4, 0, 2)) points2.append(Point(-2, 2, 0)) points2.append(Point(2, 3, -1)) points2.append(Point(3, 7, -2)) points2.append(Point(4, 9, -1)) spline2 = BSplineCurve.from_points(points2) surface = BSplineSurface.from_fill(spline1, spline2) U, V = meshgrid(surface.uspace(30), surface.vspace(20), 'ij') frames = [surface.frame_at(u, v) for u, v in zip(flatten(U[1:]), flatten(V))] # ==============================================================================
mesh.update_default_face_attributes({'overhang': 0.0}) for f_key, data in mesh.faces(data=True): face_normal = mesh.face_normal(f_key, unitized=True) data['overhang'] = Vector(0.0, 0.0, 1.0).dot(face_normal) # face looking towards the positive y axis - Boolean value (per face) mesh.update_default_face_attributes({'positive_y_axis': False}) for f_key, data in mesh.faces(data=True): face_normal = mesh.face_normal(f_key, unitized=True) is_positive_y = Vector(0.0, 1.0, 0.0).dot(face_normal) > 0 # boolean value data['positive_y_axis'] = is_positive_y # distance from plane - Scalar value (per vertex) mesh.update_default_vertex_attributes({'dist_from_plane': 0.0}) plane = (Point(0.0, 0.0, -30.0), Vector(0.0, 0.5, 0.5)) for v_key, data in mesh.vertices(data=True): v_coord = mesh.vertex_coordinates(v_key, axes='xyz') data['dist_from_plane'] = distance_point_plane(v_coord, plane) # direction towards point - Vector value (per vertex) mesh.update_default_vertex_attributes({'direction_to_pt': 0.0}) pt = Point(4.0, 1.0, 0.0) for v_key, data in mesh.vertices(data=True): v_coord = mesh.vertex_coordinates(v_key, axes='xyz') data['direction_to_pt'] = np.array( normalize_vector(Vector.from_start_end(v_coord, pt))) # --------------- Slice mesh slicer = PlanarSlicer(mesh, slicer_type="default", layer_height=5.0) slicer.slice_model()
def unroll(zone): unrolled = [] for quadmesh, trimesh in zone: flatmesh = trimesh.copy() fkeys = list(trimesh.faces_where({'count': 0})) for fkey in fkeys: nbrs = trimesh.face_neighbors(fkey) if len(nbrs) == 1: root = fkey break root = None for key in trimesh.face_vertices(root): if trimesh.vertex_degree(key) == 2: corner = key break corner = None u = corner v = trimesh.face_vertex_descendant(root, u) origin = trimesh.vertex_coordinates(u) zaxis = trimesh.face_normal(root, unitized=True) xaxis = normalize_vector(trimesh.edge_direction(u, v)) yaxis = normalize_vector(cross_vectors(zaxis, xaxis)) frame = Frame(origin, xaxis, yaxis) frame_to = Frame.worldXY() T = Transformation.from_frame_to_frame(frame, frame_to) for key in trimesh.face_vertices(root): x, y, z = trimesh.vertex_coordinates(key) point = Point(x, y, z) point.transform(T) flatmesh.set_vertex_attributes(key, 'xyz', point) tovisit = deque([root]) visited = set([root]) while tovisit: fkey = tovisit.popleft() for u, v in trimesh.face_halfedges(fkey): nbr = trimesh.halfedge[v][u] if nbr is None: continue if nbr in visited: continue tovisit.append(nbr) visited.add(nbr) origin = trimesh.vertex_coordinates(v) zaxis = trimesh.face_normal(nbr, unitized=True) xaxis = normalize_vector(trimesh.edge_direction(v, u)) yaxis = normalize_vector(cross_vectors(xaxis, zaxis)) frame = Frame(origin, xaxis, yaxis) origin = flatmesh.vertex_coordinates(v) zaxis = [0, 0, 1.0] xaxis = normalize_vector(flatmesh.edge_direction(v, u)) yaxis = normalize_vector(cross_vectors(xaxis, zaxis)) frame_to = Frame(origin, xaxis, yaxis) T = Transformation.from_frame_to_frame(frame, frame_to) w = trimesh.face_vertex_ancestor(nbr, v) x, y, z = trimesh.vertex_coordinates(w) point = Point(x, y, z) point.transform(T) flatmesh.set_vertex_attributes(w, 'xyz', point) for key, attr in quadmesh.vertices(True): x, y, z = flatmesh.vertex_coordinates(key) attr['x'] = x attr['y'] = y attr['z'] = z unrolled.append(quadmesh) return unrolled
def location(self, location): self._location = Point(*location)
from compas.geometry import Point from compas.geometry import Polyline from compas.geometry import NurbsSurface from compas.artists import Artist points = [ [Point(0, 0, 0), Point(1, 0, 0), Point(2, 0, 0), Point(3, 0, 0)], [Point(0, 1, 0), Point(1, 1, 2), Point(2, 1, 2), Point(3, 1, 0)], [Point(0, 2, 0), Point(1, 2, 2), Point(2, 2, 2), Point(3, 2, 0)], [Point(0, 3, 0), Point(1, 3, 0), Point(2, 3, 0), Point(3, 3, 0)], ] surface = NurbsSurface.from_points(points=points) # ============================================================================== # JSON Data # ============================================================================== string = surface.to_jsonstring(pretty=True)
def to_compas(self): return Point(self.x, self.y, self.z)
self.plotter.axes.update_datalim([self.point[:2]]) # ============================================================================== # Main # ============================================================================== if __name__ == '__main__': from compas.geometry import Point from compas.geometry import Translation from compas_plotters import Plotter2 plotter = Plotter2() a = Point(0.0, 0.0) b = Point(5.0, 0.0) c = Point(5.0, 5.0) T = Translation([0.1, 0.0, 0.0]) plotter.add(a, edgecolor='#ff0000') plotter.add(b, edgecolor='#00ff00') plotter.add(c, edgecolor='#0000ff') plotter.draw(pause=1.0) for i in range(100): a.transform(T) plotter.redraw(pause=0.01)
from compas.geometry import Point from compas.geometry import Vector # Point p1 = Point(1, 2, 3) assert p1 ** 3 == [1, 8, 27] assert p1 + [0, 2, 1] == [1, 4, 4] # Vector u = Vector(1, 0, 0) v = Vector(0, 1, 0) assert u + v == [1, 1, 0] assert u.dot(v) == 0.0 assert u.cross(v) == [0, 0, 1] assert (u * 2).unitized() == [1, 0, 0]
def point(self, point): self._point = Point(*point)
from compas.datastructures import Mesh from compas.rpc import Proxy from compas_rhino.artists import MeshArtist proxy = Proxy() proxy.restart_server() compas_rhino.clear() box = Box.from_width_height_depth(2, 2, 2) box = Mesh.from_shape(box) box.quads_to_triangles() A = box.to_vertices_and_faces() sphere = Sphere(Point(1, 1, 1), 1) sphere = Mesh.from_shape(sphere, u=30, v=30) sphere.quads_to_triangles() B = sphere.to_vertices_and_faces() proxy.package = "compas_cgal.meshing" B = proxy.remesh(B, 0.3, 10) proxy.package = "compas_cgal.booleans" V, F = proxy.boolean_union(A, B) mesh = Mesh.from_vertices_and_faces(V, F) artist = MeshArtist(mesh) artist.draw_faces()
# ============================================================================== # Main # ============================================================================== if __name__ == '__main__': from compas.geometry import Circle from compas.geometry import Point from compas.geometry import Plane from compas.geometry import Vector from compas.geometry import Translation from compas_plotters import GeometryPlotter plotter = GeometryPlotter() plane = Plane(Point(0, 0, 0), Vector(0, 0, 1)) a = Circle(plane, 4.0) b = Circle(plane, 3.0) c = Circle(plane, 2.0) T = Translation.from_vector([0.1, 0.0, 0.0]) plotter.add(a, edgecolor='#ff0000') plotter.add(b, edgecolor='#00ff00') plotter.add(c, edgecolor='#0000ff') plotter.pause(1.0) for i in range(100): a.transform(T)
from compas.geometry import Point from compas.geometry import Polyline, Bezier from compas_occ.geometry import OCCNurbsCurve from compas_view2.app import App from compas_view2.objects import Collection points = [Point(0, 0, 0), Point(3, 6, 0), Point(6, -3, 3), Point(10, 0, 0)] bezier = Bezier(points) points = bezier.locus(10) curve = OCCNurbsCurve.from_interpolation(points) # ============================================================================== # Visualisation # ============================================================================== view = App() view.add(Polyline(curve.locus()), linewidth=3) view.add(Collection(points)) view.run()
def location(self): """:class:`compas.geometry.Point` - The location of the Blender object.""" return Point(*self.object.location)