0

In Inkscape I have a large number of objects.

I would like to select a random subset of these objects and change their width en masse.

Is it possible to do this in Inkscape?

2
  • Hi. Welcome to GDSE. The software has no ability to automatically select objects randomly. I suppose it could be scripted, but I'm no coder. Scaling on one axis can be done using the Trasform dialog, Scale tab, and the option "apply to each separately".
    – Billy Kerr
    Jan 20 at 9:32
  • Hello, Richard, can you tell us something more and perhaps add an example? What do you expect to achieve? What efforts have you made? Jan 20 at 16:19

2 Answers 2

2

Currently, it's not possible to randomly select objects using the main GUI of Inkscape. I have created this inkscape extension to randomly select a subset of objects and change their width or height attributes:

  • Download the extension and install it.
  • Select all the objects (Make sure to convert them to paths).
  • Extensions > Modify Path > Batch property random selection

Below is a demonstration:

demonstration


More features could be added later.

1

I'd been interested in generating a star field with randomly-sized stars.

It's easy to generate nicely-distributed circles using Poisson Disc Sampling and to find SVGs where people have already done this via Google Image Search. With such an SVG in hand the question then becomes: how do I resize some of the "stars" to be larger than others. Choosing these randomly seems reasonable.

Poisson disc sampling

However, I didn't end up using the above approach. The stars were too uniformly distributed.

Instead, I downloaded bsc5.dat.gz from the Yale Bright Star Catalog.

I then passed it through the script at the bottom of this post.

This produced an image similar to this

Orthographic projection of night sky

which I can then clip as needed.

Star Generation Script

#!/usr/bin/env python3

import math
from typing import List, Optional, Tuple


class Star():
  """
  A class representing a star, with name, magnitude, right ascension (ra),
  declination (dec) and projected co-ordinates x,y calculated by a class
  method.

  """
  def __init__(self, name: str, constellation: str, mag: float, ra: float, dec: float) -> None:
    """
    Initializes the star object with its name and magnitude, and position
    as right ascension (ra) and declination (dec), both in radians.

    """
    self.name = name
    self.constellation = constellation
    self.mag = mag
    self.ra = ra
    self.dec = dec
    self.visible = True
    self.x: Optional[float] = None
    self.y: Optional[float] = None

  def project_orthographic(self, ra0: float, dec0: float) -> Tuple[float, float]:
    """
    Calculates, stores and returns the projected co-ordinates (x, y) of
    this star's position using an orthographic projection about the
    angular position (ra0, dec0).
    """

    delta_ra = self.ra - ra0
    self.x = math.cos(self.dec) * math.sin(delta_ra)
    self.y = math.sin(self.dec) * math.cos(dec0)\
          - math.cos(self.dec) * math.cos(delta_ra) * math.sin(dec0)
    return self.x, self.y

# Read in the star data
star_data = open('bsc5.dat', 'r').readlines()

# Parse all the stars into Star objects
stars: List[Star] = []
for line in star_data:
  constellation = line[11:14]
  name = line[4:14]
  try:
      mag = float(line[102:107])
  except ValueError:
      # some stars do not have magnitudes: ignore these entries
      continue
  # Right ascension (hrs, mins, secs), equinox J2000, epoch 2000.0
  ra_hrs, ra_min, ra_sec = [float(x) for x in (line[75:77], line[77:79], line[79:83])]
  # Declination (hrs, mins, secs), equinox J2000, epoch 2000.0
  dec_deg, dec_min, dec_sec = [float(x) for x in (line[83:86], line[86:88], line[88:90])]
  # Convert both RA and declination to radians
  ra = math.radians((ra_hrs + ra_min/60 + ra_sec/3600) * 15.)
  dec = math.radians(dec_deg + dec_min/60 + dec_sec/3600)
  # Create a new Star object and add it to the list of stars
  stars.append(Star(name, constellation, mag, ra, dec))

# Now find the number of stars in the Orion constellation and use this to find
# the center (average position) of the constellation
n = sum([1 for star in stars if star.constellation == "Ori"])
ra0 = sum([star.ra for star in stars if star.constellation == "Ori"]) / n
dec0 = sum([star.dec for star in stars if star.constellation == "Ori"]) / n

# Now get the projections of all of the stars when projected to an orthographic
# projection centered on the constellation
coords: List[Tuple[float, float]] = []
for star in stars:
  # Orthographic projection (ra, dec) -> (x1, y1)
  coords.append(star.project_orthographic(ra0, dec0))

# Get dimensions and aspect ratio of image
xmin = min(coords, key=lambda x: x[0])[0]
xmax = max(coords, key=lambda x: x[0])[0]
ymin = min(coords, key=lambda x: x[1])[1]
ymax = max(coords, key=lambda x: x[1])[1]
aspect_ratio = (xmax-xmin)/(ymax-ymin)

# The stars will be output on a canvas of dimensions width x height, with
# some extra padding around the outside of the "paintable" area.
padding = 50
height = 2500
width = int(height * aspect_ratio)

# Write the SVG image file for the constellation
with open('{:s}.svg'.format("/z/test.svg"), 'w') as f:
    print('<?xml version="1.0" encoding="utf-8"?>', file=f)
    print('<svg xmlns="http://www.w3.org/2000/svg"', file=f)
    print('     xmlns:xlink="http://www.w3.org/1999/xlink"', file=f)
    print('     width="{:d}" height="{:d}">' # style="background: #000000">'
            .format(width + 2*padding, height + 2*padding), file=f)
    for star in stars:
        if not star.visible:
          continue
        # Enable to filter stars by magnitude (brightness)
        # if star.mag > 4.5:
          # continue
        # Enable to filter stars by constellation
        # if star.constellation != "Ori":
          # continue
        rx = (star.x - xmin) / (xmax - xmin)
        ry = (star.y - ymin) / (ymax - ymin)
        cx = padding + (1-rx) * (width - 2*padding)
        cy = padding + (1-ry) * (height - 2*padding)
        radius = max(1, 6-star.mag) if star.constellation == "Ori" else max(1, 5-star.mag)
        print('<circle cx="{cx:.1f}" cy="{cy:.1f}" r="{r:.1f}"'
              ' stroke="none" fill="#000000" name="{name:s}"/>'.format(
              cx=cx, cy=cy, r=radius, name=star.name), file=f)
    print('</svg>', file=f)
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.